標籤:

例舉 Python 的一些坑?

首先得聲明一下,本人可不是在黑Python,事實上目前正在用Python做項目,而且在接觸Python這些時間之後,已經不大使用C++和Delphi了,因為Python在很多方面已經滿足我的工作要求。

但在使用的過程中,也碰到過一些坑,我想凡用過一段時間的人也該深有體會。Python的坑也許還有更多,很想聽到各位的見解。


我覺得Python真正能算坑的其實不多,更多是因為對於內部機制了解不深。

不過以下這個可以算真正的「坑」:

&>&> t = ([],[])
&>&> t[0] += [1] # guess what will happen?
&>&> print t # how about it now?

下面這個blog對於這個有詳細解釋,可以參考:

Stupid Python Ideas: Augmented Assignments (a += b)


我認為違背大多數人常規判斷的都屬於坑:

比如(如無特別說明,同時針對Python2.7xPython3.x):

1.

In [1]: f0, f1, f2 = [lambda x: x*i for i in range(3)]
In [2]: print f0(1), f1(1), f2(1) # ???

2.

In [1]: var = 100
In [2]: def f1():
...: locals()[var] = 200
...: print var
...:
In [3]: def f2():
...: exec "locals()[var] = 300"
...: print var
...:
In [4]: f1(), f2() #???

3.

In [1]: class Any(object):
...: def var(self): pass
...:
In [2]: obj = Any()
In [3]: obj.var == obj.var # True or False
In [4]: obj.var is obj.var # True or False
In [5]: id(obj.var) == id(obj.var) # True or False

In [6]: x, y = obj.var, obj.var
In [7]: x == y # True or False
In [8]: x is y # True or False
In [9]: id(x) == id(y) # True or False

4. 如下In3,4,5,6,7的運行結果,以及原因

In [1]: class Base(object):
...: def __init__(self):
...: self._value = 10
...: def __repr__(self):
...: return Value(%s) % self._value
...: @property
...: def value(self):
...: return self._value
...: @value.setter
...: def value(self, v):
...: self._value = v
...:

In [2]: class Derived(Base):
...: @property
...: def value(self):
...: return super(Derived, self).value * 2
...: @value.setter
...: def value(self, v):
...: super(Derived, self).value = v / 2
...:

In [3]: b, d = Base(), Derived()
In [4]: b.value, d.value
In [5]: b.value = 100
In [6]: d.value = 100
In [7]: b.value, d.value

5. 下面來一個Python3.x特有的:

In [1]: def createClsByName(name):
...: def createA():
...: class A:
...: xs, ys = ABC, 123
...: values = [x+y for x, y in zip(xs, ys)]
...: return A()
...: def createB():
...: class B:
...: xs, ys = ABC, 123
...: values = [xs[i]+ys[i] for i in range(len(xs))]
...: return B()
...: return createA() if name==A else createB()
...:

In [2]: createClsByName(A).values
Out[2]: #???

In [3]: createClsByName(B).values
Out[3]: #???


定義函數時的可選參數,實際上是個全局變數,如果寫一個引用類型的值(比如 dict / list / set)就坑爹了,比如:

def f(a, b=[]):
b.append(a)
print len(b)

f(1)

每次列印的結果都不一樣。

=================================================================

list 中兩個字元串如果不加逗號分割的話,不會報錯,而是合併為同一個字元串:

l = [
foo # 這裡沒寫逗號
bar
]

如果不小心的話很容易中招。

=================================================================

datetime 的 isoformat 方法沒有時區信息,比如:

from datetime import datetime

print datetime.now().isoformat()

結果是 2015-05-13T18:05:53.820435。這個時間是本地時間,最後也沒有時區信息,發送給其他服務去處理的時候,如果忽略時區信息,當成 UTC 時間來處理就中招了。


看起來有但其實並沒有的閉包。。。3的閉包勉強還能用,2連 nonlocal 都沒有。。。


Python中,多重繼承,parent1父類可以調用children子類的方法,也就是說可以調用子類多重繼承中另一個parent2父類的方法(繼承給了子類),而且這個方法parent1沒有定義,parent1也沒有父類(父類是object)。這樣寫有點像java的介面,因為parent1 new完以後,調用方法是會報錯,但是子類多重繼承後,因為子類從parent2繼承了該方法,所以不會出錯。於是會出現什麼問題呢,你看開源代碼的時候,有時候找不到該方法在哪裡定義,往上找繼承鏈找也找不到,這時可能需要往下找和往兩邊找(看子類或其他父類有沒有這個方法,坑。) 學過c++,Python,JavaScript,java。要說哪門簡單,我會選擇java,動態語言花樣太多


我遇到的if __name__ == __main__:判斷一直錯誤是什麼鬼→_→,剛開始代碼不執行,我還以為是我的包和模塊寫的有問題,調試的時候__name__也是__main__啊,可是一直跳過。直到我把這句話剪切又粘貼了一遍,它奇蹟般的又好了。。。神奇。


說兩個自己碰到過的吧

第一個是cPickle在Ubuntu下load大文件時的問題,會爆Memory Error,但是改用pickle之後就可以順利load,讓我從此不敢再用cPickle(伺服器用的是Ubuntu傷不起)

第二個是urllib里的quote這個函數。這個函數在python2.x和python3.x中不僅所在的包不一樣,而且如果同時安裝python2.x和python3.x,那麼python解釋器就會報錯,把爬蟲從2.x轉到3.x的時候比較坑


縮進……強迫是空格,多好,非得要個Tab

最好調成縮進可見。

複製粘貼,經常就是縮進錯


3都這麼多年,那就裝3吧,媽蛋,PIL尚不支持,找別的吧


上面也有人提到了,碰到坑的時候往往是對於Python運行的內部機制不太了解

這裡推薦個網站 Visualize Python code execution

它以可視化的形式幫助讀者加深對Python運行機制的了解

下面是運行效果截圖:


先贊一下題主沒有 spam tags。

Python 十坑:10 Most Common Python Programming Problems


說一個我自己遇到的問題,也許並不算Python有坑,只是我腦子有坑。

因為不是專門學編程的,所以養成了一些不好的習慣,比如不想要的代碼就直接注釋掉,就像下面這個例子

a = 5

wf = wave.open(r"C:UsersNotepad++xboxubuntu.wav", rb)

print(a)

用 』引起來的部分是注釋,這樣可以把一大塊代碼一次注釋掉,但是這裡會出錯:

SyntaxError: (unicode error) unicodeescape codec cant decode bytes in position 20-21: truncated UXXXXXXXX escape

原因是這裡的U被認為是unicode編碼的轉義字元(涉及到編碼我就不想看了。。。),就是說如果在注釋中包含有U的話,就會被坑,其實不只是U,包含N, x, u都是不行的(可以參考python 3.3.3 字面量,正則,反斜杠和原始字元串)。用#注釋不會出現這個問題。

就我自己分析, 本質上還是字元串的一種,因為它本身具備的特質,被借用來當做注釋,和真正的注釋還是有所區別的。

另外,把代碼修改一下:

a = 5
r
wf = wave.open(r"C:UsersNotepad++xboxubuntu.wav", rb)

print(a)

這樣不會報錯。


-1


Python3


子類不寫構造函數會自動調用父類的構造函數,寫了就不自動調用了


多線程,2傻逼一樣的utf8支持。 還有pip上若干的坑比庫。


粘貼代碼,縮進不對,無法運行!!!!

語法上還好,就是複製了別人的(或者自己以前寫的)一段代碼,粘貼在現在的代碼上,縮進不對,不能運行。關鍵是人家ide也不知道你是什麼縮進的、不知道你的if語句是內循環里還是外循環里,也無法幫你縮進,只能手動調縮進。


1.樓上說的函數默認參數問題

2.多線程 GIL

3.gc頓卡,不gc環引用內存泄露

4.python 程序相對較占內存,一個空字典就100多個位元組。py3做了改進

5.寫cpython的話,引用計數和多線程下的GIL容易坑

印象中碰到的就這些


Python的元組本來不就是以逗號區分的嗎?有沒有括弧反而是無所謂的事情,我不知道題主為什麼認為這是Python的坑


CPython的Global Interpreter Lock (GIL)


推薦閱讀:

對ldap實現增刪改查--附demo
Python 是慢,但我無所謂
python封裝阿里雲API
用100行Python爬蟲代碼抓取公開的足球數據玩(一)

TAG:Python |