Jeff Schwab a écrit : > [EMAIL PROTECTED] wrote: (snip) >> Explicitely using list.extend would make things clearer: >> >> def invoke_some_fct(parent): >> parent.x.extend(['world']) > > Whether you use += or extend has nothing to do with it.
Mmm... Really ? > You omitted the > relevant part. Using extend, it would look like: > > y = parent.x > y.extend(['world']) > > The confusing part is that performing an operation on y may or may not > alter parent.x, depending on whether the initial type of parent.x is > immutable. given that Python doesn't copy anything unless explicitelly asked for, the y = parent.x statement has the very clear semantic of making y an alias of parent.x. Mutability has nothing to do with it, except for the fact that if parent.x is immutable there's indeed no way to mutate it. > If parent.x is immutable, y is a copy of the value > represented by parent.x, No, by no way. >>> class Parent(object): pass ... >>> p = Parent() >>> p.x = "aaa + bbb " # a string that won't be interned >>> y = p.x >>> y is p.x True y is *not* "a copy of x", it is another name bound to the very same object. > and modifying y has not effect on the value of > parent.x. Your problem is with the semantic of "modifying". In Python, (re)binding a name and mutating an object are two very distinct things. If (the object referenced by) y is immutable, you *can not* modify (=> mutate) it. Period. And if you *rebind* y, this *won't* affect p.x, whether it's mutable or not: >>> p = Parent() >>> p.x = ['allo'] >>> y = p.x >>> y is p.x True >>> y = ['la terre'] >>> y ['la terre'] >>> p.x ['allo'] >>> y is p.x False >>> IOW - and while, you're right about this, I skipped the part that trouble you, that is the aliasing of parent.x -, the observation that using list.extend (that is, clearly a mutator method call) instead of augmented assignment which *looks like* it's rebinding y (and would effectively rebind it if y was immutable). FWIW, it's IMHO a real wart - given Python's pretention at readability - that augmented assignement has been implemented that way for lists. > If (OTOH) parent.x is mutable, then x and y are really > references to the same object, and modifications to that object via y > can be observed via x. In C, you use pointers to get this effect. Not quite the same thing. C variables are boxes (containing values), with pointer's values being the coords of another box, while Python's 'variables' are only labels on objects - they *never* 'contains' anything. (FWIW, someone recently posted a link to a very good explanation of this, but I don't have it under hand right now - could someone help ?) With pointers, a function can modify the content of a box defined in the caller's scope. This is not something you can do in Python - that is, rebinding a formal parameter to a different object withing a function won't affect the bindings in the caller's scope: def rebinder(x): print "before: x = %s (id: %s)" % (x, id(x)) x = ['bar'] print "after: x = %s (id: %s)" % (x, id(x)) def caller(): a = ['foo'] print "before: a = %s (id: %s)" % (a, id(a)) rebinder(a) print "after: a = %s (id: %s)" % (a, id(a)) caller() > >> Now there's no reason to feel nervous about this. All you have to >> remember is that Python never copy anything unless explicitely asked >> for. > > It's not that simple. After a statement like: > > a = b > > Whether a and b denote the same object depends on what kind of object b > represented in the first place. No. You can bet your life on this : after this statement, a and b are two labels for the very same object, *always*, *whatever* the type of b. Now this is a very frequent cause of confusion for C/C++ programmers, and it has been explained again and again here - usually far better than I just did, so you may want to google for this. HTH -- http://mail.python.org/mailman/listinfo/python-list