Something in the function tutorial confused me.

A

Aahz

This sentence is phrased as though it is the whole story, but it
isn't, because the operation might not in fact wind up being an
assignment. Shouldn't there be an "except see below" or something
there, to alert the reader that in some cases a true assignment doesn't
occur? (I realize that the exception follows quite closely on the heels
of this sentence, but it doesn't follow immediately, and is separated by
a paragraph break and intervening material about the parallel to
unaugmented x = x + 1. On initial reading my tendency is to read the
end of the sentence quoted above, see a paragraph break and apparently
explanatory material, and go "oh, okay, I now have the full
specification of this syntax" when in fact I don't.)

That's a good idea -- doc patches are always welcome!
 
A

Aahz

I used to interpret the target in 'The target is only evaluated once'
more like an L-value in C/C++. That's not correct, of course, but I
didn't understand exactly how wrong it was until now.

It's true almost everywhere except augmented assignment. Augmented
assignment is a prime example of the compromises one needs to make in
adding features.
 
D

David Wahler

I too thought += was an assignment. And it bit me very painfully a few weeks ago.

If it's an assignment, then wouldn't "x += y" mean the same thing as "x = x + y"?

If so, why does an assignment to variable a, below, have the *side effect* of changing variable b ... ?
a = [1, 2, 3]
b = a
b [1, 2, 3]
a += [4]
a [1, 2, 3, 4]
b
[1, 2, 3, 4]

... but using the "x = x + y" style, the assignment to variable c, below, does *not* have a side effect on variable d (as indeed it should not!)?
c = [1, 2, 3]
d = c
d [1, 2, 3]
c = c + [4]
c [1, 2, 3, 4]
d
[1, 2, 3]
help(list.__iadd__)
Help on wrapper_descriptor:

__iadd__(...)
x.__iadd__(y) <==> x+=y

For mutable (built-in) objects such as lists, __iadd__ modifies the
list and then returns the list object; for immutable objects, __iadd__
is equivalent to __add__ and just returns the new value. However, in
both cases, the result is then rebound to x. This can lead to some
behaviors you might not normally expect:
Traceback (most recent call last):
([1],)

-- David
 
N

Neil Cerutti

Neil Cerutti said:
The Python Language Reference seems a little confused about
the terminology.

3.4.7 Emulating numeric types
6.3.1 Augmented assignment statements

The former refers to "augmented arithmetic operations", which
I think is a nice terminology, since assignment is not
necessarily taking place. Then the latter muddies the waters.

Assignment *IS* "necessarily taking place"; if you try the
augmented assignment on something that DOESN'T support
assignment, you'll get an exception. Consider:
tup=([],)
tup[0] += ['zap']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

Tuples don't support item ASSIGNMENT, and += is an ASSIGNMENT,
so tuples don't allow a += on any of their items.

If you thought that += wasn't an assignment, this behavior and
error message would be very problematic; since the language
reference ISN'T confused and has things quite right, this
behavior and error message are perfectly consistent and clear.

Thanks for the correction. I was under the illusion that
sometimes augmented assignment would instead mutate the object.

OK, I've thought about this some more and I think the source of
my confusion was I thought assignment in Python meant binding a
name to something, not mutating an object. But in the case of
augmented assignment, assignment no longer means that?
 
A

Alex Martelli

Neil Cerutti said:
OK, I've thought about this some more and I think the source of
my confusion was I thought assignment in Python meant binding a
name to something, not mutating an object. But in the case of
augmented assignment, assignment no longer means that?

"Plain" assignment *to a plain name* does mean "binding a name" (the
LHS) to "something" (the RHS).

Other assignments (ones that are not "plain" assignments to names) may
have different meanings. For example:
.... def __init__(self, c): self._c = c
.... def getC(self): return self._c
.... def setC(self, *ignore): self._c += 1
.... c = property(getC, setC)
....
Here's an example where a plain assignment (to an attribute of x, not to
a plain name) obviously DOESN'T mean "binding a name to something": the
"something" (the RHS) is completely ignored, so the plain assignment is
mutating an object (x) and not binding any name to anything.

Plain assignments to items and slices can also often be best seen as
"mutating an object" (the one being indexed or sliced on the LHS) rather
than "binding a name". For example:
['c', 'a', 'p', 'p', 'o']

If I was teaching Python and came upon this example, I would definitely
not try to weaselword the explanation of what's going on in terms of
"binding a name" (or several ``names'', including ``rebinding" a new
``name'' l[4] to the 'o' that was previously ``bound'' to l[3], etc:):
it's just orders of magnitudes simpler to explain this as "mutating an
object", namely the list l.

I take almost 3 pages in "Python in a Nutshell" (47 to 49 in the second
edition) to summarily explain every kind assignment -- and that's in a
work in which I've tried (successfully, I believe from reviews) to be
very, *VERY* concise;-).

Summarizing that summary;-), a plain assignment to an identifier binds
that name; a plain assignment to an attribute reference x.y asks object
x (x can be any expression) to bind its attribute named 'y'; a plain
assignment to an indexing x[y] (x and y are arbitrary expressions) asks
object x to bind its item indicated by the value of y); a plain
assignment to a slicing is equivalent to the plain assignment to the
indexing with an index of slice(start, stop, stride) [[slice is a Python
builtin type]].

Plain assignment to an identifier "just happens"; all other cases of
plain assignment are requests to an object to bind one or more of its
attributes or items (i.e., requests for specific mutations of an object)
-- as for, say any method call (which might also be a request for some
kind of mutation), the object will do whatever it pleases with the
request (including, perhaps, "refusing" it, by raising an exception).

Then we get into unpacking assignments and augmented assignments, but I
don't really want to write two more pages worth of summary...;-).


Alex
 
N

Neil Cerutti

"Plain" assignment *to a plain name* does mean "binding a name"
(the LHS) to "something" (the RHS).

Other assignments (ones that are not "plain" assignments to
names) may have different meanings. For example:

... def __init__(self, c): self._c = c
... def getC(self): return self._c
... def setC(self, *ignore): self._c += 1
... c = property(getC, setC)
...
1

Here's an example where a plain assignment (to an attribute of x, not to
a plain name) obviously DOESN'T mean "binding a name to something": the
"something" (the RHS) is completely ignored, so the plain assignment is
mutating an object (x) and not binding any name to anything.

That's enlightening. I hadn't considered the implications of
generalizing assignment to names with assignment to qualified
names.
Plain assignments to items and slices can also often be best
seen as "mutating an object" (the one being indexed or sliced
l=list('ciao')
l[1:3]='app'
l
['c', 'a', 'p', 'p', 'o']

That example makes me feel ashamed for not thinking of it, since
I use the slicing assignment all the time and it's "obviously"
not a binding construct.
If I was teaching Python and came upon this example, I would
definitely not try to weaselword the explanation of what's
going on in terms of "binding a name" (or several ``names'',
including ``rebinding" a new ``name'' l[4] to the 'o' that was
previously ``bound'' to l[3], etc:): it's just orders of
magnitudes simpler to explain this as "mutating an object",
namely the list

I take almost 3 pages in "Python in a Nutshell" (47 to 49 in
the second edition) to summarily explain every kind assignment
-- and that's in a work in which I've tried (successfully, I
believe from reviews) to be very, *VERY* concise;-).

Summarizing that summary;-), a plain assignment to an identifier binds
that name; a plain assignment to an attribute reference x.y asks object
x (x can be any expression) to bind its attribute named 'y'; a plain
assignment to an indexing x[y] (x and y are arbitrary expressions) asks
object x to bind its item indicated by the value of y); a plain
assignment to a slicing is equivalent to the plain assignment to the
indexing with an index of slice(start, stop, stride) [[slice is a Python
builtin type]].

Plain assignment to an identifier "just happens"; all other cases of
plain assignment are requests to an object to bind one or more of its
attributes or items (i.e., requests for specific mutations of an object)
-- as for, say any method call (which might also be a request for some
kind of mutation), the object will do whatever it pleases with the
request (including, perhaps, "refusing" it, by raising an exception).

Then we get into unpacking assignments and augmented
assignments, but I don't really want to write two more pages
worth of summary...;-).

Thanks very much for taking the time to help clear up my
erroneous model of assignment in Python. I'd taken a conceptual
shortcut that's not justified.
 
A

Alex Martelli

Neil Cerutti said:
Thanks very much for taking the time to help clear up my
erroneous model of assignment in Python. I'd taken a conceptual
shortcut that's not justified.

You're very welcome, it's always a pleasure to help!


Alex
 
?

=?ISO-8859-1?Q?Ricardo_Ar=E1oz?=

Aahz said:
Sometimes that precise search pattern isn't appropriate, of course. ;-)

Sorry, will answer as soon as I read the 52000 hits for "Aahz python".
Be patient ;c)
 
K

kyosohma

Sorry, will answer as soon as I read the 52000 hits for "Aahz python".
Be patient ;c)

No offense to Steven but Alex has over twice as many hits. Gives the
rest of us something to shoot for, eh?

Mike
 
S

Steve Holden

No offense to Steven but Alex has over twice as many hits. Gives the
rest of us something to shoot for, eh?
No offense taken: Alex won the award before me!

regards
Steve
--
Steve Holden +1 571 484 6266 +1 800 494 3119
Holden Web LLC/Ltd http://www.holdenweb.com
Skype: holdenweb http://del.icio.us/steve.holden
--------------- Asciimercial ------------------
Get on the web: Blog, lens and tag the Internet
Many services currently offer free registration
----------- Thank You for Reading -------------
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,794
Messages
2,569,641
Members
45,354
Latest member
OrenKrause

Latest Threads

Top