On Fri, Apr 28, 2017 at 03:30:29PM +1000, Chris Angelico wrote:

> > Obviously we can define syntax to do anything we like, but what is the
> > logical connection between the syntax and the semantics? What part of
> > "function parameter list" suggests "assign attributes to arbitrary
> > objects"?
[...]
> What part of a 'for' loop suggests that you can do this?

I'm not sure what "this" is supposed to do. You've written some 
obscure but perfectly legal Python code:

> odds = [0]*10; evens = [0]*10
> for idx, (odds if idx%2 else evens)[idx//2] in stuff:
>     ...

My guess is that "this" refers to the side-effect that assigning to a 
list item updates the list item. Um, yeah, it does. What's your point? 
Of course it does. That's what its supposed to do.

Perhaps you think that there's something weird about using an arbitrary 
assignment target as the for-loop. I don't know why you think that's 
weird. Here's a simpler example:

for obj.attr in seq:
    ...

Yes, its a bit unusual to do that, but its not weird. The assignment 
target for a loop is just an ordinary assignment target, and the 
assignment occurs during the execution of code, just like any other 
assignment that occurs inside the body of the function.

What is weird is to have the function *declaration* have global side 
effects and perform assignments outside of the function. The parameter 
list is *not* a general assignment statement, it is a declaration of 
what local variables will be assigned to when you call the function.

In Python 3, function paramaters are plain (non-qualified) 
identifiers, not general assignment targets. Even in Python 2, the most 
that was supported were tuple-unpacking. Even that can be read as 
conceptually just a declaration:

    def func(a, (x,y)):

declares that the first argument is a, and the second argument is a pair 
of values x and y. But this proposal has to be read as a declaration 
plus a separate assignment:

    def func(a, spam.x):

declares that the second argument is called "x", (but not spam.x), and 
*in addition* there will be an assignment spam.x = x at some point, 
presumably before the function body gets entered.


> Nothing whatsoever says that this is a good idea, but it's perfectly
> legal, because the for loop is defined in terms of assignment. If this
> were to be accepted (which, fwiw, I'm not actually advocating, but
> IF), it would also be defined in terms of assignment.

Why should it be defined in terms of general assignment? That's the 
point I'm making. While function sigs are a form of assignment, they're 
more of a declaration than an executable statement like the other 
binding statements. There's a superficial connection, but they really 
are quite different things.

(For example: if you allow spam.foo as a parameter, that can call 
arbitrary Python code in spam.__setattr__, which assigning to foo as a 
parameter will not do.)


> You still
> shouldn't be assigning to arbitrary objects, especially not randomly
> rebinding module names, but it's easy to grok the assignment
> equivalence.

You need to speak to more beginners if you think the connection between 
spam.x and x is obvious:

    def func(spam.x):
        print(x)

Where is x declared? It looks like there's a local spam.x which isn't 
used, and a global x that is. But that's completely wrong. Without the 
context of somebody telling you "this is syntax for magically assigning 
to self.attributes in the constructor", I believe this will be 
unfathomable to the average non-expert.


> And yes, it WOULD reinstate the argument unpacking removed by PEP
> 3113. So for this to go forward, the objections in that PEP would have
> to be addressed.

Nicely remembered :-)



-- 
Steve
_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to