1 下面的代碼輸出什麼。
list = ['a', 'b', 'c', 'd', 'e']print list[10:]
上面的代碼輸出[],並且不會導致IndexError錯誤
跟你想的一樣,當取列表元素的時候,如果索引值超過了元素的個數(例如在上面的列表中,取list[10])將會導致IndexError錯誤。但是,取一個列表的切片的時候,如果起始索引超過了元素個數,將不會引起IndexError錯誤,僅返回一個空列表。
這一特性將會導致一些非常難於追蹤的bug,因為在運行時根本沒有錯誤產生。 2下面的代碼在Python2中的輸出是什麼。解釋你的答案
def div1(x,y): print "%s/%s = %s" % (x, y, x/y)def div2(x,y): print "%s//%s = %s" % (x, y, x//y)div1(5,2)div1(5.,2)div2(5,2)div2(5.,2.)
另外,在Python3中上面的代碼的輸出有何不同(假設代碼中的print語句都轉化成了Python3中的文法結構)。
在Python2中,代碼的輸出是:
5/2 = 25.0/2 = 2.55//2 = 25.0//2.0 = 2.0
預設情況下,如果兩個運算元都是整數,Python2預設執行整數運算。所以,5/2 結果是2,而5./2結果是2.5
注意你可以通過下面的import語句來覆蓋Python2中的這一行為
from __future__ import division
還要注意“雙斜杠”(//)操作符將會一直執行整除,忽略運算元的類型。這就是為什麼5.0//2.0即使在Python2中結果也是2.0
但是在Python3兩個運算元都是整數時,也不執行整數運算。在Python3中,輸出如下:
單斜杠在python2預設整除但是可以型別提升,pyhton3一律按照浮點操作。
5/2 = 2.55.0/2 = 2.55//2 = 25.0//2.0 = 2.0
3下面代碼的輸出是什麼。請解釋你的答案
def extendList(val, list=[]): list.append(val) return listlist1 = extendList(10)list2 = extendList(123,[])list3 = extendList('a')print "list1 = %s" % list1print "list2 = %s" % list2print "list3 = %s" % list3
如何修改函數ExtendList的定義才能產生我們希望的行為。
輸出為:
list1 = [10, 'a']list2 = [123]list3 = [10, 'a']
很多人會錯誤地預計list1等於[10],list3等於['a'],認為extendList函數的list參數在每一次函數被調用時都會被設定為預設值[]
但是,真實的情況是,預設的list只在函數定義的時候被建立一次。之後不指定list參數地調用extendList函數時,使用的都是同一個list。這是因為預設參數在函數定義的時候被計算的,而不是在函數調用時。
question:既然Python的預設參數都是在定義時計算的,下次調用時會調用統一個list,那最後一個怎麼不得24呢。。。
所以,list1和list3都是在操作同一個預設list,而list2是在操作它自己建立的一個獨立的list(將自己的空list作為參數傳遞過去)
extendlist的定義可以這樣定義來達到我們預期的效果:
def extendList(val, list=None): if list is None: list = [] list.append(val) return list
調用修改後的函數,輸出是:
list1 = [10]list2 = [123]list3 = ['a']
4下面代碼的輸出是什麼。請解釋你的答案
class Parent(object): x = 1class Child1(Parent): passclass Child2(Parent): passprint Parent.x, Child1.x, Child2.xChild1.x = 2print Parent.x, Child1.x, Child2.xParent.x = 3print Parent.x, Child1.x, Child2.x
輸出為:
1 1 11 2 13 2 3
讓很多人感到疑惑和驚訝的是,最後一行的輸出竟然不是3 2 1而是3 2 3. 為什麼修改了Parent.X的值會影響到Child2.x,但是同時又沒有改變Child1.x的值呢。
這個問題的關鍵在於,在python中,類中的變數在內部被當作字典處理。如果一個變數名在當前類的字典中沒有被發現,系統將會在這個類的祖先(例如,它的父類)中繼續尋找,直到找到為止(如果一個變數名在這個類和這個類的祖先中都沒有,那麼將會引發一個AttributeError錯誤)
因此,在父類中將變數x賦值為1,那麼x變數將可以被當前類和所有這個類的子類引用。這就是為什麼第一個print語句輸出為1 1 1.
接下來,如果它的子類覆蓋了這個值(例如, 當我們執行Child1.x = 2),那麼這個變數的值僅僅在這個子類中發生了改變。這就是為什麼第二個print語句輸出1 2 1
最後,如果父類改變了這個變數的值(例如,我們執行Parent.x = 3),所有沒有覆蓋這個參數值的子類(在這個例子中覆蓋了參數的就是Child2)都會受到影響,這就是為什麼第三個print語句的輸出為3 2 3 5下面代碼的輸出是什麼。請解釋你的答案
def multipliers(): return [lambda x : i * x for i in range(4)]print [m(2) for m in multipliers()]
怎麼修改multipliers的定義才能達到期望的效果。
上面代碼的輸出是[6, 6, 6, 6](不是[0, 2, 4, 6]).
原因是Python的閉包是延遲綁定(late binding)的。這表明在閉包中使用的變數直到內層函數被調用的時候才會被尋找。結果是,當調用multipliers()返回的函數時,i參數的值會在這時被在調用環境中尋找。所以,無論調用返回的哪個函數,for迴圈此時已經結束,i等於它最終的值3。因此,所有返回的函數都要乘以傳遞過來的3,因為上面的代碼傳遞了2作為參數,所以他們都返回了6(即,3 * 2)
(順便提一句,正如在書《The Hitchhiker’s Guide to Python》中提出來的一樣, 有一種廣泛傳播的誤解認為這個問題和lambda運算式有關,事實並非如此。通過labda運算式產生的函數並沒有什麼特別之處,使用普通的def定義的函數的行為和lambda運算式產生的函數的行為是一樣的.)
下面是一些可以繞過這個問題的方法。
方法一是像下面一樣使用Python的產生器(generator)
def multipliers(): for i