Florian Daniel Otel wrote: > Do I understand it correctly > that actually the rule has to be refined as pertaining to the (so > called) "immutable" types (like e.g. integers, tuples/strings) > whereas lists and dictionaries are "mutable" types and the said > scoping rule does not apply ?
No! The only difference between mutable and immutable objects are that the value of mutable objects can be changed after object creation. The thing you need to understand is how variables, objects and assignments work in Python! We are always dealing with references to objects in Python. In e.g. C, the code "int c; c=1; c=2;" roughly means: Make a place for an integer in memory, and let's refer to that place as "c". Then place the value 1 in c. Finally, replace the value 1 with the value 2 in c. This isn't at all how Python works. I think of C variables as differently shaped (typed) boxes with a label glued onto the side, but I think of Python variables as a tag or label tied to a string (string as in thin rope, not text). The other end of that string is tied to an object in a big, shared storage room. C assignments mean that you make a copy of some data and put in a box, discarding whatever was previously in that box. Python assignment means that you untie a string from an object and tie it to another (possibly newly created) object. When an object no longer has any strings attached, it's (usually) considered to be garbage. So, in Python, "c=1; c=2" means that you have a variable (or name) called c in the current namespace. That's not a place for some kind of object as in C, it's just a name that can be bound to some object in that shared storage room that we nerds call the heap. First, c will be bound to, or refer to, an integer object on the heap containing the value 1. Then c will be rebound to another object, 2. In C, you have your different boxes neatly stacked in various namespaces. In Python the boxes are all in one place, but your labels are neatly organized in various namespaces. You can make "strings" like this in C too, they are called pointers, but it's not automatic as in Python, and C pointers are much more difficult and error prone. So, returning to your question, scoping rules are just the same. The issue with mutable object are that they can be mutated. Different variables in different namespaces can refer to the same object. E.g. >>> l = [1,2] >>> def addToList1(aList, value): ... aList.append(value) ... return aList ... >>> def addToList2(aList, value): ... newList = aList + [value] ... return newList ... >>> print l [1, 2] >>> print id(l) 182894638800 >>> l1=addToList1(l,3) >>> print l, l1 [1, 2, 3] [1, 2, 3] >>> print id(l), id(l1) 182894638800 182894638800 >>> l2=addToList2(l,4) >>> print l, l2 [1, 2, 3] [1, 2, 3, 4] >>> print id(l), id(l2) 182894638800 182894638736 You see? Calling addToList1 caused the list object that was passed in to be modified. This modification is obviously seen by all variables that are bound to that object, whatever namespace they exist in. Calling addToList2 doesn't cause any modification of the objects that the parameters are bound to. Instead a new object is created. With immutable objects, you can't possibly do something along the lines of addToList1. This means that if x is bound to an immutable object, x will always have the same value before and after a call to f(x), whatever code function f contains. If x is mutable, you have no such guarantees. It depends on f... It's not only variables that can be bound to objects. E.g: >>> l1 = [] >>> l2 = [l1] >>> t1 = [l1] >>> print l1, l2, t1 [] [[]] [[]] >>> t1[0].append(1) >>> print l1, l2, t1 [1] [[1]] [[1]] l1, position 0 in l2 and position 0 in t1 are all bound to the same object, an initially empty list. -- http://mail.python.org/mailman/listinfo/python-list