python的一些誤區

原文連接放在這裏:1: http://nafiulis.me/potential-pythonic-pitfalls.html
不少問題沒搞懂,先放在這裏,慢慢改。
python是一門很是有趣的語言。它提供了許多很是方便的標準庫和許多內置命令是咱們輕鬆完成任務.可是好東西太多了就有選擇恐懼症了,以致於咱們不能很好第利用這個標準庫和它的基本機構。下面列出了一些對python新手來講很簡單有效的陷阱。html


忽略了python的版本

這是一個在StackOverflow上不斷被人提起的問題。當你完美的代碼跑在別人的電腦上就報錯是怎樣一種體驗,因此這個時候就須要檢查大家的python版本是否一致。確保代碼跑在本身知道的python版本上。你能夠經過如下代碼查看python版本:python

$ python --version
Python 2.7.9

python版本管理

pyenv是一個不錯的python版本管理工具。不幸的是它只運行在*nix系統上。在Mac OS上,你能夠簡單用brew install pyenv安裝,在linux系統中,有一個自動安裝器automatic installerlinux

糾結於用一行代碼解決全部問題

許多人誇口說我多牛用一行代碼就解決了全部問題,即使他們的代碼比正常寫的更缺乏效率,並且這些代碼也會更難以閱讀,甚至會出現歧義。好比說:c++

l = [m for a, b in zip(this, that) if b.method(a) != b for m in b if not m.method(a, b) and reduce(lambda x, y: a + y.method(), (m, a, b))]

老實說上面的代碼是我本身爲了說明這件事情寫的。可是我但是真的見過有許多人這樣幹過。若是你只是簡單經過把東西添加到一個list或者一個set中來顯擺本身解決複雜問題的手段,那麼你有可能會得不償失。git

一行代碼控並非什麼巨大的成就,儘管有時候看起來特別聰明。優秀的代碼是簡潔可是更注重高效和易讀。github

錯誤地初始化set

這是一個更加微妙的問題,有時候會讓你措手不及。set推導式起來有點像list推導式.app

>>> { n for n in range(10) if n % 2 == 0 }
{0, 8, 2, 4, 6}
>>> type({ n for n in range(10) if n % 2 == 0 })
<class 'set'>

上面的例子說明了這點。set有點像放在容器中的list
它們的區別是set沒有重複的值和無序的。人們一般會把{}認爲是一個空的set,可它不是,它是一個空的dict.函數

>>> {}
{}
>>> type({})
<class 'dict'>

因此若是咱們想要初始化一個空的set,就直接使用set()工具

>>> set()
set()
>>> type(set())
<class 'set'>

注意一個空的set能夠表示成set(),可是一個包含了元素的集合要被定義成set([1, 2])的樣子。this


誤解了GIL

GIL(全局解釋器鎖)意味着只有一個線程在一個Python程序能夠運行在任什麼時候間。 這意味着當咱們不能建立一個線程,並指望它並行運行。 Python解釋器實際上作的是快速切換不一樣的運行線程。 但這是一個很是簡單的版本。 在許多實例中程序並行運行,像使用C擴展的庫時。 但Python代碼運行時,大多數時候不會並行執行。換句話說,線程在Python中不像在Java或c++中同樣。

許多人會嘗試爲Python辯解說,這些都是真正的線程。 3 這確實是真的,但並不能改變這樣一個事實:Python處理線程的方式不一樣於你指望的那樣。 Ruby也有相似的狀況(還有一個解釋器鎖)。

規定的解決方案是使用multiprocessing模塊。multiprocessing模塊提供的過程類基本上能夠很好地覆蓋分歧。 然而,分歧比線程代價高得多。因此並行運行不老是好的。

然而,這個問題不是每一個Python程序都會遇到。PyPy-stm就是Python的一個實現不受GIL影響的例子。 實現創建在其餘平臺上的像JVM(Jython) 或CLR(IronPython)沒有GIL的問題。

總之,在使用時要當心線程類,你獲得的可能不是你想要的。

使用過期的樣式類

在Python 2有兩種類型的類,「舊式」類,「新風格」類。 若是 你使用Python 3,那麼你正在使用默認的「新風格」類。 爲了確保你使用 「新風格」在Python 2類,您須要繼承object或者任何你建立的不老是繼承內建指令intlist的新類 。 換句話說,你的基類,應該老是繼承object

class MyNewObject(object):
    # stuff here

這些'新類'修復了一些很是基本的出如今老式類中問題,若是你感興趣能夠查看文檔

錯誤的迭代

下面的這些錯誤對新手來講很是常見:

for name_index in range(len(names)):
    print(names[name_index])

很明顯沒有必要使用len, 實際上遍歷列表用很是簡單的語句就能夠實現:

for name in names:
    print(name)

此外,還有一大堆其餘的工具在你處理簡化迭代。 例如,zip能夠用來遍歷兩個列表:

for cat, dog in zip(cats, dogs):
    print(cat, dog)

若是咱們要考慮索引和值列表變量,咱們可使用enumerate

for index, cat in enumerate(cats):
    print(cat, index)

itertools中還有不少功能能夠選擇。若是itertools中有你想要的功能就很方便的拿來用。可是也不要過於爲了用它而用它。

itertools濫用使得StackOverflow上的一個大神花了不少時間去解決它。

使用了可變的默認參數

我看過不少以下:

def foo(a, b, c=[]):
    # append to c
    # do some more stuff

不要使用可變的默認參數,而不是使用如下:

def foo(a, b, c=None):
    if c is None:
        c = []
    # append to c
    # do some more stuff

下面這個例子能夠很直觀地幫咱們理解這個問題:

In[2]: def foo(a, b, c=[]):
...     c.append(a)
...     c.append(b)
...     print(c)
...
In[3]: foo(1, 1)
[1, 1]
In[4]: foo(1, 1)
[1, 1, 1, 1]
In[5]: foo(1, 1)
[1, 1, 1, 1, 1, 1]

相同的 c 被引用一次又一次的每一次調用該函數。 這可能會產生一些很是 沒必要要的後果。

相關文章
相關標籤/搜索