[tips] python2與python 3的list comprehensions之差異
剛好看到這篇
http://yz.mit.edu/wp/2010/01/14/bitten-by-python-scoping/
想起之前也有遇到類似的問題~
其實主要就是python2的list comprehensions有個副作用,
就是會重設scope內的變數, 比如以下這個程式
def t1():
x=5
[0 for x in [1,2,3]]
print x
t1()
3
這邊的x會被重設為3, 有點像是殘餘的loop變數的感覺~
有些人會玩弄這個副作用來達到一些不想讓人看懂的lambda技巧就是了:P
但相對來說後來引進的generator語法就沒有這個問題, 所以這個問題其實也可以使用list(x for x in [1,2,3])這個方法來解決.
def ts2():
x=5
list(x for x in [1,2,3])
print x
ts2()
5
另外也可以置換變數比如改成使用a來取代x(當然a是會被assigned).
當然還有另外一個方法則是使用python 3, 就完全沒有這個問題了 :D
5 則留言:
越來越偷懶了
Hi, 拜讀過您在 Django 初接教學的影片後, 非常感謝您的speech帶給我的幫助. 最後想問這個article討論的內容是不是因為 list comprehension 是有 local scope 的function, 才會去改變相對於被當作global variable x的value?
當然在tl function外, x 自然是local 變數, 另外自己做了一個測試:
def tl():
x = 5
j = 9
tl.x = 20
[0 for tl.x in [1,2,3]]
print x
tl()
print tl.x
print j
j 會有error, 為何tl.x 不會有呢?
是因為把call tl.x 當作call method底下的local var嗎?
最後這樣tl.x 在外部能算是object嘛?
還是這只是調用method下name是x的變數而已?
python 是相當純物件導向的語言,跟之前學過的java 和c 來講, 需要釐清一些細部觀念, 在此感謝指教。
list comprehension並不是function而是個statement,不過在python2裡卻有影響scope內同名變數的副作用, 這個問題在python3已經被解決了, 此外你提的測試中, 因為tl被python視為一個function object,所以x雖然是local variable,tl.x則被視為是其class variable,x跟tl.x是兩個不同scope的變數,而j本身也是個local variable, 所以x,j都無法在function的scope外被存取到,但tl.x可以. 希望這樣有回答到你的問題.
"因為tl被python視為一個function object,所以x雖然是local variable,tl.x則被視為是其class variable,x跟tl.x是兩個不同scope的變數,"
非常critcial 的point, 這樣來看python是所有的一切都是object.
我在做了個測試補上 print tl.a得到了這個結果,
AttributeError: 'function' object has no attribute 'a'
最後試著解釋一下:整個"tl.x"是class variable, x is local var, 但兩者變數是共用同一個值20, That means different var name and type but reference the same value?
x =20;
def tl2():
x=15
print x
tl2()
print tl2.x
>>>AttributeError: 'function' object has no attribute 'x'
用這個範例我清楚明白了.這樣有error,所以兩個變數是完全不同的,一個是class var,another is local var, scope決定了這個var的visible range. 在global scope產生的var是能被local scope存取. 感謝您的解釋 : )
張貼留言