I'm new to Python and am trying to understand its approach to variable scope. In this example, why is f() able to alter the value of x, as perceived within main(), but not the value of n?
def f(n, x):
n = 2
x.append(4)
print 'In f():', n, x
def main():
n = 1
x = [0,1,2,3]
print 'Before:', n, x
f(n, x)
print 'After: ', n, x
main()
Output:
Before: 1 [0, 1, 2, 3]
In f(): 2 [0, 1, 2, 3, 4]
After: 1 [0, 1, 2, 3, 4]
-
fdoesn't actually alter the value ofx(which is always the same reference to an instance of a list). Rather, it alters the contents of this list.In both cases, a copy is passed to the function. But since
xis a reference to a list instance, only the reference is copied, not the contents of the list.In case you are familiar with C, the following approaches the semantics of the Python code:
void f(int n, int* x) { n = 42; x[0] = 2; }Here,
nis anintandxis anint*but both are passed as a copy to the function. Nontheless, the memory pointed to byxis the same at the sides of the caller and the callee.J.F. Sebastian : "copy" is misleading. Python doesn't have variables like C. All names in Python are references. You can't modify name, you just can bind it to another object, that's all. It only makes sense to talk about mutable and immutable *object* in Python not they are names.dysfunctor : @J.F. Sebastian: Your statement is misleading at best. It is not useful to think of numbers as being references.S.Lott : @dysfunctor: numbers are references to immutable objects. If you'd rather think of them some other way, you have a bunch of odd special cases to explain. If you think of them as immutable, there are no special cases.dysfunctor : @S.Lott: Regardless of what's going on under the hood, Guido van Rossum put a lot of effort into designing Python so that the programmer can thing of numbers as being just ... numbers.Aaron Gallagher : @J.F., the reference is copied.J.F. Sebastian : @Aaron: It might or might not be so. Underlying implementation can construct a new object that represents a name in Python and then bind it to corresponding object. C is not the only implementation language. You can implement Python in pure Python. -
It´s because a list is a mutable object. You´re not setting x to the value of [0,1,2,3], you´re defining a label to the object [0,1,2,3].
You should declare your function f() like this:
def f(n, x=None): if x is None: x = [] ... -
n is an int (immutable), and a copy is passed to the function, so in the function you are changing the copy.
X is a list (mutable), and a copy of the pointer is passed o the function so x.append(4) changes the contents of the list. However, you you said x = [0,1,2,3,4] in your function, you would not change the contents of x in main().
S.Lott : Watch the "copy of the pointer" phrasing. Both places get references to the objects. n is a reference to an immutable object; x is a reference to a mutable object. -
I will rename variables to reduce confusion. n -> nf or nmain. x -> xf or xmain:
def f(nf, xf): nf = 2 xf.append(4) print 'In f():', nf, xf def main(): nmain = 1 xmain = [0,1,2,3] print 'Before:', nmain, xmain f(nmain, xmain) print 'After: ', nmain, xmain main()When you call the function f, the Python runtime makes a copy of xmain and assigns it to xf, and similarly assigns a copy of nmain to nf.
In the case of n, the value that is copied is 1.
In the case of x the value that is copied is not the literal list [0, 1, 2, 3]. It is a reference to that list. xf and xmain are pointing at the same list, so when you modify xf you are also modifying xmain.
If, however, you were to write something like:
xf = ["foo", "bar"] xf.append(4)you would find that xmain has not changed. This is because, in the line xf = ["foo", "bar"] you have change xf to point to a new list. Any changes you make to this new list will have no effects on the list that xmain still points to.
Hope that helps. :-)
-
Some answers contain a word "copy" in a context of a function call. I find it confusing.
Python doesn't copy objects you pass during a function call ever.
Function parameters are names. When you call a function Python binds these parameters to whatever objects you pass (via names in a caller scope).
Objects can be mutable (like lists) or immutable (like integers, strings in Python). Mutable object you can change. You can't change a name, you just can bind it to another object.
Your example is not about scopes or namespaces, it is about naming and binding and mutability of an object in Python.
def f(n, x): # these `n`, `x` have nothing to do with `n` and `x` from main() n = 2 # put `n` label on `2` balloon x.append(4) # call `append` method of whatever object `x` is referring to. print 'In f():', n, x x = [] # put `x` label on `[]` ballon # the above has no effect on the original listHere's nice pictures on the difference between variables in other languages and names in Python.
Cawas : +1 for great referencing links on top of the nice explanation -
You've got a number of answers already, and I broadly agree with J.F. Sebastian, but you might find this useful as a shortcut:
Any time you see
varname =, you're creating a new variable (or name) within the function's scope. Whatever valuevarnamehad before is lost within this scope.Any time you see
varname.foo()you're calling a method onvarname. The method may alter varname (e.g.list.append).varname(or, rather, the object thatvarnamenames) may exist in more than one scope, and since it's the same object, any changes will be visible in all scopes.[note that the
globalkeyword creates an exception to the first case]
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.