2016-09-16 64 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)這樣的東西,因爲沒有辦法給它賦值。