list to table

Gabriel Genellina gagsl-py2 at yahoo.com.ar
Fri Nov 6 01:26:52 EST 2009


En Thu, 05 Nov 2009 21:23:27 -0300, Alf P. Steinbach <alfps at start.no>  
escribió:
> * Jon Clements:

> This sent me searching everywhere, because the documentation of '+=' and  
> other "augmented assignment statements" says
>
>    "The target is only evaluated once.",
>
> like in C++, which implies a kind of reference to mutable object.

Not exactly. For an augmented assignment, the target (left side) may be an  
identifier, an atttribute reference, or a subscription/slicing. In the  
first case, the comment simply does not apply (there is a single one  
opportunity to evaluate the target).

a += some(expression) means: evaluate "a", evaluate some(expression),  
perform the operation +=, bind the resulting object to the name "a".

a.attr += some(expression) means: evaluate "a", ask it for its attribute  
"attr", evaluate some(expression), perform the operation +=, ask the  
(already known) object "a" to store the resulting object as its attribute  
"attr".

a[index] += some(expression) performs a similar sequence of steps; "a" is  
evaluated only once, then it is asked to retrieve its element at [index],  
the computation is performed, and finally the (already known) object "a"  
is asked to store the result at [index].

"The target is only evaluated once." means that it is NOT reevaluated  
before the final result is stored. Same applies to "index" above, although  
this is not explicited. Perhaps it is more clear with a longer expression:  
a[b+c].c[d(e[f])].h += 1 computes the a[b+c].c[d(e[f])] part only once.

> I couldn't immediately see how subscription could apparently return a  
> reference to mutable int object in Python in a way so that it worked  
> transparently (the idiom in C++).

It does not. It perform first a "getitem" operation followed by a  
"setitem" to store the result. A normal dictionary would fail when asked  
for an inexistent item; a defaultdict creates and returns a default value  
in such case.

py> import collections
py> d = collections.defaultdict(int)
py> d['a'] += 1
py> d['a'] += 1
py> d['a']
2
py> d['b']
0

note: int() returns 0; defaultdict(lambda: 0) could have been used.

> However, it worked to replace collections.defaultdict with a class  
> overriding __getitem__ and __setitem__, so I guess that's how it works,  
> that in this case '+=' is simply translated like 'x += n' -> 'temp = x;  
> x = temp + n'.
>
> Is this a correct understanding, and if so, what exactly does the  
> documentation mean for the general case?

If x is a simple name, the only difference between x += n and x = x+n is  
the method invoked to perform the operation (__iadd__ vs __add__ in  
arbitrary objects). Both x and n are evaluated only once - and this is not  
an optimization, nor a shortcut, simply there is no need to do otherwise  
(please make sure you understand this).

 From the docs for the operator module: "Many operations have an “in-place”  
version. The following functions provide a more primitive access to  
in-place operators than the usual syntax does; for example, the statement  
x += y is equivalent to x = operator.iadd(x, y). Another way to put it is  
to say that z = operator.iadd(x, y) is equivalent to the compound  
statement z = x; z += y."
http://docs.python.org/library/operator.html

> foo()[bar()] += 1
>
> so here it's not translated like 'foo()[bar()] = foo()[bar()] + 1' but  
> evidently more like 'a = foo(); i = bar(); a.__setitem__(i,  
> a.__getitem__(i) + 1)'?

Yes, something like that.

> If so, is this behavior defined anywhere?

Isn't the description at  
http://docs.python.org/reference/simple_stmts.html#assignment-statements  
enough? It goes to some detail describing, e.g., what a.x = 1 means. The  
next section explains what a.x += 1 means in terms of the former case.

> I did find discussion (end of §6.2 of the language reference) of the  
> case where the target is an attibute reference, with this example:
>
> class A:
>      x = 3    # class variable
> a = A()
> a.x += 1     # writes a.x as 4 leaving A.x as 3

Do you want to discuss this example?

-- 
Gabriel Genellina




More information about the Python-list mailing list