2016-09-16 48 views
3

在CPython 2.7.10和3.4.3以及PyPy 2.6.0(Python 2.7.9)中,为for循环中的名称列表使用表达式(或其中的一些子集)显然是合法的。下面是一个典型的循环:for循环名称列表表达式是否合法?

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

但你也可以使用属性的对象:

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

你甚至可以从表达式中使用属性:

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

但并不是所有的表达式似乎工作:

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

但是只要属性在外面,他们就会这样做?

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

或者什么是可分配的?

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

我很惊讶这些都是Python中的合法语法。我希望只有名字被允许。这些甚至应该工作吗?这是一个疏忽吗?这是Pyyy恰好也实现了CPython的实现细节吗?

+0

是((True and obj).e =“hello”'有效的语法? –

+0

......回答我自己的问题:不,事实并非如此。 –

+0

在dictionary.items()中为'k,v做些什么? –

回答

5

这些甚至应该工作吗?

这是一个疏忽?

没有

这是CPython中的实现细节,PyPy恰好也 实现?

没有


如果你能分配给它,你可以使用它作为在for循环中游离不定。

对于这样的问题,这是值得直行到grammar

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

一个target_list只是一堆的target

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

如果你在那仔细观察,你会看到你给出的例子都不是反例。请注意,解析器中的错误并非闻所未闻(even I found one once),所以如果您发现合法的语法异常,那么通过提交一张票 - 这些错误往往会很快得到修复。

你给我的最有趣的是一对和(True and obj.d)(True and obj).d,这似乎是逻辑上是相同但分析不同:

>>> 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()))])" 

注:(True and obj).d是在语法的attributeref

1

documented,在for语法“可变”可以是任何target_list,其中,因为also documented指任何可以在一个赋值语句的左手侧。你显然不能使用像(True and obj.d)这样的东西,因为没有办法给它赋值。