Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
210 views
in Technique[技术] by (71.8m points)

python - Are for-loop name list expressions legal?

In CPython 2.7.10 and 3.4.3, and PyPy 2.6.0 (Python 2.7.9), it is apparently legal to use expressions (or some subset of them) for the name list in a for-loop. Here's a typical for-loop:

>>> for a in [1]: pass
...
>>> a
1

But you can also use attributes from objects:

>>> class Obj(object): pass
...
>>> obj = Obj()
>>> for obj.b in [1]: pass
...
>>> obj.b
1

And you can even use attributes from expressions:

>>> for Obj().c in [1]: pass
...

But not all expressions appear to work:

>>> for (True and obj.d) in [1]: pass
...
  File "<stdin>", line 1
SyntaxError: can't assign to operator

But they do so long as the attribute is on the outside?

>>> for (True and obj).e in [1]: pass
...
>>> obj.e
1

Or something is assignable?

>>> for {}['f'] in [1]: pass
...

I'm surprised any of these are legal syntax in Python. I expected only names to be allowed. Are these even supposed to work? Is this an oversight? Is this an implementation detail of CPython that PyPy happens to also implement?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Are these even supposed to work?

Yes

Is this an oversight?

No

Is this an implementation detail of CPython that PyPy happens to also implement?

No


If you can assign to it, you can use it as the free variable in the for loop.

For questions like this, it's worth going straight to the grammar:

for_stmt ::=  "for" target_list "in" expression_list ":" suite
              ["else" ":" suite]

A target_list is just a bunch of target:

target_list     ::=  target ("," target)* [","]
target          ::=  identifier
                     | "(" target_list ")"
                     | "[" [target_list] "]"
                     | attributeref
                     | subscription
                     | slicing
                     | "*" target

If you look at that closely, you'll see that none of the working examples you've given is a counter-example. Mind you, bugs in the parser are not unheard of (even I found one once), so if you find a legitimate syntax anomaly then by means submit a ticket - these tend to get fixed quickly.

The most interesting pair you gave is (True and obj.d) and (True and obj).d, which seem to be the same logically but are parsed differently:

>>> ast.dump(ast.parse('(True and obj.d)'), annotate_fields=False)
"Module([Expr(BoolOp(And(), [Name('True', Load()), Attribute(Name('obj', Load()), 'd', Load())]))])"
>>> ast.dump(ast.parse('(True and obj).d'), annotate_fields=False)
"Module([Expr(Attribute(BoolOp(And(), [Name('True', Load()), Name('obj', Load())]), 'd', Load()))])"

Note: (True and obj).d is an attributeref in the grammar.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...