On 7/4/2018 9:35 AM, Steven D'Aprano wrote:
On Wed, Jul 04, 2018 at 05:02:07PM +1000, Chris Angelico wrote:
On Wed, Jul 4, 2018 at 4:07 PM, Serhiy Storchaka <storch...@gmail.com> wrote:

"Assignment is a statement" -- that's exactly the point under discussion.

I believe that this is Chris quoting and commenting on Serhiy having said 'assigment is a statement'

Not any more it isn't. We've now gone from discussion to bitter
recriminations *wink*

I don't see any recrimination in what either said.

"del is a statement" -- yes, granted

"function and class declarations are statements" -- class, yes, but
you have "def" and "lambda" as statement and expression equivalents.

Even class can be re-written as a call to type(), if you need to. It's
probably not practical to do so in anything but the simplest cases, but
it is there.

Serhiy's viewpoint is a legitimate one. A major difference between def, class, and import statements and equivalent lambda, type, and __import__ expressions is that the latter do not name-bind the resulting object. This will continue to be true.

There is, however, precedent for subverting "assignment is a statement".

>>> class C():
        pass

>>> c = C()
>>> c.a = 1
>>> setattr(c, 'b', 2)
>>> c.b
2

However, the target name, when given explicitly, is quoted. This preserves the general rule that non-keyword identifiers in expressions are immediately evaluated. The current exceptions are the 'and', 'or', and 'if-else' constructs that embed flow control in expressions. But if a name in such expressions is not ignored, it is evaluated normally.

The purpose of setattr is to allow the target attribute name to be any variable or expression that evaluates to a string, so that one can do the following.

>>> d = 'c'
>>> setattr(c, d+'2', 3)
>>> c.c2
3

or even

>>> setattr(c, input('aname: '), 33)
aname: qr
>>> c.qr
33

(An allowed side-effect is the possibility of adding attributes, such as '2e', that can only be recovered with getattr.)

The same comments apply to globals().update({'foo':42}), pointed out by David Merz in another post. (This specific form does not work does not work within functions, as pointed out by Chris Angelico. But others do.)


A major difference between a while loop statement and an equivalent tail recursion call (expression) is that while loops do explicit assignment in the current namespace while recursive calls do implicit assignment in a new (and unneeded) execution frame. The targets are the unquoted parameter names in the function header. I regard the the easy use of unevaluated unquoted names as a justification for having statements in addition to expressions.


An alternate assignment-within-expressions proposal would be to follow the setattr precedent. Add a builtin function 'set' with paramenters 'name' and 'value'. It would have to be built-in because Python code cannot directly access function local namespaces. The problem, aside from extra typing, is that efficient implementation of functions requires that all local names be known at compile time. But a name added by "set(input('name: '), <expr>)" is impossible to know.

Making the assignment target be an unquoted unevaluated non-keyword name immediately followed by ':=' solves this. But it either introduces a new and different type of exception to 'names in expressions are evaluated', or one must regard 'assignment expression' as a new statement-expression hybrid. Advocates of assignment expressions should not really be surprised that this disquiets some people.

--
Terry Jan Reedy

_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com

Reply via email to