Python 3000 idea: reversing the order of chained assignments

S

Steve Holden

Duncan said:
http://docs.python.org/ref/assignment.html

More specifically, since you seem to have missed it, it's the '+' in the
line:

assignment_stmt ::= (target_list "=")+ expression_list

And then the clear statement "assigns the single resulting object to each
of the target lists, from left to right".

Got it, thanks. See my further remarks in my reply to your last.

regards
Steve
 
S

Steve Holden

Duncan said:
That is precisely the point. If it was:

assignment_stmt ::= (target_list "=") expression_list |
(target_list "=") assignment_stmt

(i.e. removing the '+' which your eyes jumped over)
then the actual assignments would have to apply right to left with each
assignment giving the result for the next one.

But since it is:

assignment_stmt ::= (target_list "=")+ expression_list

the repeated target lists may be expected, and are indeed defined, to
assign left to right.

Thanks, I see the plus sign now and appreciate that it indicates "one or
more of", so the syntax is correct. But syntax doesn't imply semantics,
so a left-recursive or right-recursive syntax formulation wouldn't
require any change to the semantics of assignment.

In other words,

assignment_stmt ::= (target_list "=") expression_list |
(target_list "=") assignment_stmt

and

assignment_stmt ::= (target_list "=") assignment_stmt |
(target_list "=") expression_list

are entirely equivalent, and neither imply any order of execution. I'm
sure you understand that syntax only specifies what's legal, not how it
should be interpreted.

regards
Steve
 
D

Duncan Booth

In other words,

assignment_stmt ::= (target_list "=") expression_list |
(target_list "=") assignment_stmt

and

assignment_stmt ::= (target_list "=") assignment_stmt |
(target_list "=") expression_list

are entirely equivalent

I'm not quite sure what you are getting at. An assigment_stmt and an
expression_list are not ambiguous so those two productions are identical
(not just equivalent). Perhaps you are thinking of productions like:

m_expr ::= u_expr | m_expr "*" u_expr

which will match the same input, but could produce a different parser
output than:

m_expr ::= u_expr | u_expr "*" m_expr

I'm sure you understand that syntax only specifies what's legal, not how
it should be interpreted.

I agree that the syntax does not mandate how it should be interpreted,
but it does lead to expectations.

If the expression_stmt is hidden from the outer assignment_stmt by an inner
one then it is reasonable to expect that the inner production will be
completely evaluated before the outer assignment happens. i.e. right to
left.
 
J

John Nagle

Mark said:
John Nagle said:
Marcin Ciura wrote:

Neither would I. I must have expressed myself not clearly enough.
Currently
x = y = z
is roughly equivalent to
x = z
y = z
I propose to change it to
y = z
x = z

Actually, it is equivalent to

y = z
x = y


Not really:
class chatty(object):

... def __init__(self): self.__dict__['__hide'] = {}
... def __setattr__(self, name, value):
... print 'sa', name, value
... self.__dict__['__hide'][name] = value
... def __getattr__(self, name):
... print 'ga', name
... return self.__dict__['__hide'].get(name)
...
c = chatty()
x = c.zop = 23

sa zop 23

As you can see, there is no read-access to c.zop, which plays the role
of y there.


Alex


This is interesting:

... def __getattribute__(self,n):
... print 'reading',n
... return object.__getattribute__(self,n)
... def __setattr__(self,n,v):
... print 'writing',n,v
... return object.__setattr__(self,n,v)
...

writing a 1
writing b 2
writing c 3

reading c
writing a 3
writing b 3

I wouldn't have expected "a" to be assigned first in a right-to-left
parsing order. The result is the same in any case.

-Mark T.

That's fascinating. Is that a documented feature of the language,
or a quirk of the CPython interpreter?

John Nagle
 
Z

Ziga Seilnacht

John said:
That's fascinating. Is that a documented feature of the language,
or a quirk of the CPython interpreter?
Its a documented feature of the language. From the Reference Manual:

"An assignment statement evaluates the expression list (remember that
this can be a single expression or a comma-separated list, the latter
yielding a tuple) and assigns the single resulting object to each of
the target lists, from left to right."

See: http://docs.python.org/ref/assignment.html

Ziga
 
E

Erik Johnson

Well, I think I am thoroughly confused now. I am a lot less experienced
that most of the people posting in this thread, so perhaps that is to be
expected, but I actually thought I understood Python fairly well. Maybe I am
fooling myself...

Let me rename some variables in the code above to something a little
easier to follow:

At this point I beleive I've got the same thing above, just with different
reference names. Namely, I have two objects, and three references, the
first and third reference now both referring to the first object, the second
reference referring to the second object:
<__main__.Node instance at 0x7ff1d20c>

The discussion is about multiple assignments. Virgil's example should be
equivalent to:

n1 = n1.next = n2

If assignment were left to right, (i.e., n1 = n1.next, followed by
n1.next = n2), then I would expect to get an attribute error because n1
hasn't had the 'next' attribute attached to it yet. That's not what
happens, so the other interpretation is that the statement above is
equivalent to: n1.next = n2; n1= n1.next (except that n1.next is only
evaluated once, but that doesn't matter here). Right? That is, first object
'n1' gets a new attribute, the value of which is a reference to object n2,
and then, the name 'n1' is rebound to be a reference to object n2 (note that
the object n1 was previously referencing should still be available via name
'n3', and being a mutable object, the new attribute should be visible via
'n3', right?

I didn't yet execute the statement above (I just typed it in this
post) - let's first check the objects and attributes for what we have prior
to this confusing statement:
dir(n1) ['__doc__', '__module__']
dir(n2) ['__doc__', '__module__']
dir(n3)
['__doc__', '__module__']

Right... no suprises there. Let's execute that funky statement...

We would expect n1 to reference n2 now (my object at ...d10c), which it
does:
<__main__.Node instance at 0x7ff1d10c>

And we would expect n3 to still be referencing the object at ...d20c, which
it also still does:
<__main__.Node instance at 0x7ff1d20c>

And we would expect (or I should say "I would expect") n3 to now have a
'next' attribute:
['__doc__', '__module__']

It doesn't, which is what Virgil previously pointed out. I'm not quite
following the whole discussion (nor the syntax diagrams), so sorry if this
was already explined - could someone try again: why is it that n3 here
doesn't get the 'next' attribute?

Now here's the part that totally floors me: what would you expect to be
the attributes on n2 (the object on the far-right of the multi-way
assignment statement)? We've made no assigment statements to anything about
n2. They should be the same as before, right?
dir(n2) ['__doc__', '__module__', 'next']
n2.next

DUH.... I'm about speechless... Is it just me being dense, or is there some
obvious reason why one would expect this?
 
E

Erik Johnson

Actually, after studying this a bit more:
http://docs.python.org/ref/assignment.html

I guess that makes sense. Sorry if I muddied the water for anyone else in my
boat:

n1 = n1.next = n2

The first thing that happens is the expression list is evaluated which is
the thing on the far right, n2. That is a simple object reference which is
then assigned to each of the target lists, left to right, of which there are
two: n1 and n1.next.

So, first, n1 is assigned the same value n2 has.

Next, n1.next is assigned n2 (The object n1 refers to, which is also now n2,
is assigned a new attribute, that value of which is n2).

So, yeah... as Terry Reedy said: better to be explicit about what you want
to happen first and not mash them together into one line.

That would be... how do you say... "Pythonic"?

(God, I feel so much better now. LOL)
 
T

Terry Reedy

| Terry Reedy wrote:
| > The assignment order is specified in the language reference.
|
| Where? I'm looking at
|
| http://docs.python.org/ref/assignment.html
|
| right now.

The first line of the syntax grammar is:
assignment_stmt ::= (target_list "=")+ expression_list

The '+' means 1 or more 'target_list =' occurances.

The first line of the semantic explanation is:

" An assignment statement evaluates the expression list (...) and assigns
the single resulting object to each of the target lists, from left to
right."

Left to right.

And one can also check the byte code: 1 0 LOAD_NAME 0 (c)
3 DUP_TOP
4 STORE_NAME 1 (a)
7 STORE_NAME 2 (b)
10 LOAD_CONST 0 (None)
13 RETURN_VALUE

| as valid assignments, but I can't find the part where
|
| a = b = c
|
| is defined. Help me out here. It looks as though the real syntax should
| be something like
|
| assignment_stmt ::= (target_list "=")+ expression_list |
| (target_list "=")+ assignment_stmt

You only need the first line (see above).

Terry Jan Reedy
 

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,774
Messages
2,569,598
Members
45,152
Latest member
LorettaGur
Top