Return value of an assignment statement?

Bruno Desthuilliers bruno.42.desthuilliers at wtf.websiteburo.oops.com
Fri Feb 22 04:45:26 EST 2008


Jeff Schwab a écrit :
> bruno.desthuilliers at gmail.com 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



More information about the Python-list mailing list