【收藏】Python實用技巧-成爲Pythoner必經之路

前言  
    本文主要記錄 Python 中一些經常使用技巧,所描述的是告訴你怎麼寫纔是更好?  若是你並不熟悉Python語法,但願你能在下面代碼片斷中看到Python的簡單、優雅; 若是你象我這樣,對 Python 有興趣或並正在學習,我相信下面的技巧並不會讓你失望; 若是你已是一名 Pythoner ,那麼很樂於你分享你的經驗和技巧。 

目錄  
  • Python 禪道
  • 代碼風格: 提升可讀性
  • PEP 8: Python 代碼風格指南
  • 空格(行)使用 (1)
  • 空格(行)使用 (2)
  • 命名
  • 較長代碼行
  • 較長字符串
  • 複合語句
  • 字符串文檔 & 註釋
  • 交換變量
  • 更多關於 Tuples
  • 關於 "_"
  • 建立String: 從列表中建立
  • 儘量的使用
  • 字典中的 get 函數
  • 字典中的 setdefault 函數 (1)
  • 字典中的 setdefault 函數 (2)
  • defaultdict
  • 建立 & 分割字典
  • 判斷 True 值
  • True 值
  • 索引 & 項 (1)
  • 索引 & 項 (2): enumerate
  • 默認參數值
  • 列表理解
  • 生成器表達式 (1)
  • 生成器表達式 (2)
  • 排序
  • 使用 DSU *排序
  • 使用 Key 排序
  • 生成器
  • 生成器示例
  • 從文件中讀取數據行
  • try/except 示例
  • 導入(Importing)
  • 模塊 & 腳本
  • 模塊結構
  • 命令行處理
  • 簡單比複雜好
  • 不要從新發明輪子


章節  

Python 禪道  
這是Python的指導原則,但有不一樣詮釋。 

若是您使用的一種編程語言是以小品喜劇藝術團命名的,你最好有幽默感。  

美麗優於醜陋。 
明確優於含蓄。 
簡單比複雜好。 
平倘優於嵌套。 
稀疏比密集更好。 
特殊狀況不能特殊到打破規則。 
錯誤不該該默默傳遞。 
...... 


代碼風格: 提升可讀性  
Programs must be written for people to read, and only incidentally for machines to execute. 
     —Abelson & Sussman, Structure and Interpretation of Computer Programs 


PEP 8: Python 代碼風格指南  
值得閱讀: 
http://www.python.org/dev/peps/pep-0008/  


空格(行)使用 (1)  
  • 使用 4 個空格縮進。
  • 不要使用製表符。
  • 不要將製表符和空格混合使用。
  • IDEL和Emacs的Python的都支持 spaces模式。
  • 每一個函數之間應該有一個空行。
  • 每個 Class 之間應該有兩個空行。


空格(行)使用 (2)  
  • 在使用 字典(dict), 列表(list), 元組(tuple), 參數(argument)列表時, 應在 "," 前添加一個空格, 而且使用字典(dict)時,在 ":" 號後添加空格,而不是在前面添加。
  • 在括號以前或參數以前不添加空格。
  • 在文檔註釋中先後應該沒有空格。

Python代碼    收藏代碼
  1. def make_squares(key, value=0):  
  2.     """Return a dictionary and a list..."""  
  3.     d = {key: value}  
  4.     l = [key, value]  
  5.     return d, l  


命名  
  • joined_lower 能夠是 函數名, 方法名, 屬性名
  • joined_lower or ALL_CAPS 是常量
  • StudlyCaps 類名
  • camelCase 只有在預先制定好的命名規範使用
  • 屬性: interface_internal__private
  • 但儘可能避免__private形式。下面兩個連接解釋了 爲何python中沒有 private聲明?
       http://stackoverflow.com/questions/70528/why-are-pythons-private-methods-not-actually-private  
       http://stackoverflow.com/questions/1641219/does-python-have-private-variables-in-classes  


較長代碼行  
保持一行代碼在 80 個字符長度。 
在括號內使用隱含的行延續: 
Python代碼    收藏代碼
  1. def __init__(self, first, second, third,  
  2.             fourth, fifth, sixth):  
  3.    output = (first + second + third  
  4.              + fourth + fifth + sixth)  

或者在須要換行的位置使用 \ 來延續行: 
Python代碼    收藏代碼
  1. VeryLong.left_hand_side \  
  2.     = even_longer.right_hand_side()  
另外,使用反斜槓是有風險的,若是你添加一個空格在反斜槓後面,它就出錯了。此外,它使代碼難看。 


較長字符串  
將相鄰的字符串進行鏈接的作法: 
Python代碼    收藏代碼
  1. >>> print 'o' 'n' "e"  
  2. one  

雖然字符之間的空格不是必需的,可是這樣有助於可讀性。 
Python代碼    收藏代碼
  1. >>> print 't' r'\/\/' """o"""  
  2. t\/\/o  

用一個 「r「 開頭的字符串是一個「raw「的字符串(相似java中的轉義符)。上面的反斜槓就會當成普通字符串處理。他們對正則表達式和Windows文件系統路徑很是有用。 
注意:使用字符串變量名沒法經過以上方式進行鏈接。 
Python代碼    收藏代碼
  1. >>> a = 'three'  
  2. >>> b = 'four'  
  3. >>> a b  
  4.   File "<stdin>", line 1  
  5.     a b  
  6.       ^  
  7. SyntaxError: invalid syntax  

這是由於自動鏈接是由Python解析器/編譯器來處理的,由於其沒法在編譯時對變量值進行"翻譯",因此就這種必須在運行時使用「+「運算符來鏈接變量。 


複合語句  
Good: 
Python代碼    收藏代碼
  1. if foo == 'blah':  
  2.     do_something()  
  3. do_one()  
  4. do_two()  
  5. do_three()  

Bad: 
Python代碼    收藏代碼
  1. if foo == 'blah': do_something()  
  2. do_one(); do_two(); do_three()  


文檔註釋(Docstrings) & 註釋  
文檔註釋 = 用於解釋如何使用代碼 
      文檔註釋公約: http://www.python.org/dev/peps/pep-0257/  
註釋 = 爲何 (理由) & 代碼如何工做的如: 
Python代碼    收藏代碼
  1. # !!! BUG: ...  
  2. # !!! FIX: This is a hack  
  3. # ??? Why is this here?  
註釋對於任何語言開發者來講已經最基本的東西了,這裏就不詳細說了. 


交換變量  
在其它語言的交換變量的作法通常是: 
Java代碼    收藏代碼
  1. temp = a  
  2. a = b  
  3. b = temp  

Python的作法: 
Python代碼    收藏代碼
  1. b, a = a, b  

也許你見到過這樣的狀況,可是你知道它是如何工做的嗎? 
  • 首先,逗號是元組構造語法。
  • 等號的右邊是定義一個元組 (tuple packing).
  • 其左邊爲一個目標元組 (tuple unpacking)).
右邊的元組根據名稱被 unpacked 到左邊的無組。 
更多關於 unpacked例子: 
Python代碼    收藏代碼
  1. >>> info =['David''Pythonista''+1250']  
  2. >>> name, title, phone = info  
  3. >>> name  
  4. 'Davids'  
  5. >>> title  
  6. 'Pythonista'  
  7. >>> phone  
  8. '+1250'  

在結構化的數據上使用循環: 
info 是在上面定義的一個 list . 因此下面的 people 有兩個項,  兩個項都是分別都擁有三個項的 list. 
Python代碼    收藏代碼
  1. >>> people = [info, ['Guido''BDFL''unlisted']]  
  2. >>> for (name, title, phone) in people:  
  3. ...     print name, phone  
  4. ...  
  5. David +1250  
  6. Guido unlisted  

以上循環中,people中的兩個項(list item),都已經被 unpacked 到 (name, title, phone) 無組中。 
能夠任意嵌套(只要左右兩邊的結構必定要可以匹配得上): 
Python代碼    收藏代碼
  1. >>> david, (gname, gtitle, gphone) = people  
  2. >>> gname  
  3. 'Guido'  
  4. >>> gtitle  
  5. 'BDFL'  
  6. >>> gphone  
  7. 'unlisted'  
  8. >>> david  
  9. ['David''Pythonista''+1250']  


更多關於 Tuples  
咱們看到的是元組經過逗號構造,而不是括號。例如: 
Python代碼    收藏代碼
  1. >>> 1,  
  2. (1,)  

Python的解釋器會爲你顯示括號,因此建議你使用括號: 
Python代碼    收藏代碼
  1. >>> (1,)  
  2. (1,)  

千萬不要忘記逗號! 
Python代碼    收藏代碼
  1. >>> (1)  
  2. 1  

在只有一個元素的元組,尾隨逗號是必須的,在2 + 元素的元組,尾隨逗號是可選的。 若是建立一個 0或空元組,一對括號是快捷的語法: 
Python代碼    收藏代碼
  1. >>> ()  
  2. ()  
  3. >>> tuple()  
  4. ()  

一個常見的錯誤當你並不想要一個無組,卻無心的添加了一個逗號,很容易形成你在代碼中的錯誤,如: 
Python代碼    收藏代碼
  1. >>> value = 1,  
  2. >>> value # is a tuple, not a int  
  3. (1,)  

因此,當你發現一個元組時,趕忙去找一下那個,號吧。 


關於 "_"  
是一個很是有用的功能,可是卻不多有人知道。 
當你在交互式模式下(如 IDEL)計算一個表達式或調用一個函數後,其結果必然是一個臨時名稱,_(下劃線): 
Python代碼    收藏代碼
  1. >>> 1 + 1  
  2. 2  
  3. >>> _  
  4. 2  

在 _ 中存儲最後輸出的值。 
當輸出的結果是 None 或沒有任何輸出時,而 _ 的值並不會改變,仍然保存上一次的值。這就是方便所在。 
固然,這隻能交互式的模式中使用,在模塊中不能支持。 
這在交互式模式中是很是有用的,當你在過程當中沒有保存計算結果 或 你想看最後一步的執行的輸出結果: 
Python代碼    收藏代碼
  1. >>> import math  
  2. >>> math.pi / 3  
  3. 1.0471975511965976  
  4. >>> angle = _  
  5. >>> math.cos(angle)  
  6. 0.50000000000000011  
  7. >>> _  
  8. 0.50000000000000011  


建立String: 從列表中建立  
開始定義一個 string  列表:
Python代碼    收藏代碼
  1. colors = ['red''blue''green''yellow']  
當咱們須要將上面的列表鏈接成一個字符串。尤爲當 list 是一個很大的列表時.... 
不要這樣作: 
Python代碼    收藏代碼
  1. result = ''  
  2. for s in colors:  
  3.     result += s  
這種方式效率很是低下的,它有可怕的內存使用問題,至於爲何,若是你是 javaer 的話,其中的 string 鏈接,我想你並不陌生。 
相反,你應該這樣作: 
Python代碼    收藏代碼
  1. result = ''.join(colors)  

當你只有幾十或幾百個string項鍊接時,它們效率上並不會太大的差異。但你要在養成寫高效代碼的習慣,由於當字符串數千時,join 比起 for 鏈接性能會能有所提高。 

若是你須要使用一個函數來生成一個字符串列表,一樣可使用:
Python代碼    收藏代碼
  1. result = ''.join(fn(i) for i in items)  



儘量的使用  
Good:
Python代碼    收藏代碼
  1. for key in d:  
  2.     print key  

  • 使用 in 通常狀況下是很是快的。
  • 這種方式也適用於其它的容器對象(如 list,tuple 和 set)。
  • in 是操做符(正如上面所看到的)。

Bad: 
Python代碼    收藏代碼
  1. for key in d.keys():  
  2.     print key  

保持與上面的一致性,使用 use key in dict 方式,而不是 dict.has_key(): 
Python代碼    收藏代碼
  1.  # do this:  
  2. if key in d:  
  3.     ...do something with d[key]  
  4.   
  5. # not this:  
  6. if d.has_key(key):  
  7.     ...do something with d[key]  



字典中的 get 函數  
咱們常常須要在字典中初始化數據: 
如下是很差的實現方法: 
Python代碼    收藏代碼
  1. navs = {}  
  2. for (portfolio, equity, position) in data:  
  3.     if portfolio not in navs:  
  4.         navs[portfolio] = 0  
  5.     navs[portfolio] += position * prices[equity]  

使用dict.get(key, default) 刪除 if 判斷代碼: 
Python代碼    收藏代碼
  1. navs = {}  
  2. for (portfolio, equity, position) in data:  
  3.     navs[portfolio] = (navs.get(portfolio, 0)  
  4.                        + position * prices[equity])  
這種方式更爲直接。 


字典中的 setdefault 函數 (1)  
當咱們要初始化一個可變字典的值。每一個字典的值將是一個列表。下面是很差的作法: 
初始化可變字典的值: 
Python代碼    收藏代碼
  1. equities = {}  
  2. for (portfolio, equity) in data:  
  3.     if portfolio in equities:  
  4.         equities[portfolio].append(equity)  
  5.     else:  
  6.         equities[portfolio] = [equity]  

經過 dict.setdefault(key, default) 使這段代碼工做的更好: 
Python代碼    收藏代碼
  1. equities = {}  
  2. for (portfolio, equity) in data:  
  3.     equities.setdefault(portfolio, []).append(  
  4.                                          equity)  

dict.setdefault()等同於「 get, or set & get「 或"若是沒有,就設置";  若是你的字典Key是複雜的計算或long類型,使用 setdefault 是特別有效的。 


字典中的 setdefault 函數 (2) 
在咱們看到的setdefault字典方法也能夠做爲一個獨立的語句使用: 
Python代碼    收藏代碼
  1. avs = {}  
  2. for (portfolio, equity, position) in data:  
  3.     navs.setdefault(portfolio, 0)  
  4.     navs[portfolio] += position * prices[equity]  

咱們在這裏忽略了字典的setdefault方法返回的默認值。咱們正利用的setdefault中的做用,僅僅只是在dict中沒有 key 的值的時候纔會設置。 


建立 & 分割字典  
若是你有兩份 list 對象,但願經過這兩個對象構建一個 dict 對象。 
Python代碼    收藏代碼
  1. given = ['John''Eric''Terry''Michael']  
  2. family = ['Cleese''Idle''Gilliam''Palin']  
  3. pythons = dict(zip(given, family))  
  4. >>> pprint.pprint(pythons)  
  5. {'John''Cleese',  
  6.  'Michael''Palin',  
  7.  'Eric''Idle',  
  8.  'Terry''Gilliam'}  

一樣,若是但願獲取兩份列表,也是很是簡單: 
Python代碼    收藏代碼
  1. >>> pythons.keys()  
  2. ['John''Michael''Eric''Terry']  
  3. >>> pythons.values()  
  4. ['Cleese''Palin''Idle''Gilliam']  

須要注意的是,上面 list 雖然是有序的,可是 dict 中的  keys 和 values 是無序的,這正是由於 dict 本質就是無序存儲的。 


索引 & 項 (1)  
若是你須要一個列表,這裏有一個可愛的方式來節省你的輸入: 
Python代碼    收藏代碼
  1. >>> items = 'zero one two three'.split()  
  2. >>> print items  
  3. ['zero''one''two''three']  

若是咱們須要遍歷這個 list ,並且須要 index 和 item: 
Python代碼    收藏代碼
  1.                   - or -  
  2. i = 0  
  3. for item in items:      for i in range(len(items)):  
  4.     print i, item               print i, items[i]  
  5.     i += 1  


索引 & 項 (2): enumerate  
經過 enumerate 能夠返回 list 中的 (index, item)元組: 
Python代碼    收藏代碼
  1. >>> print list(enumerate(items))  
  2. [(0'zero'), (1'one'), (2'two'), (3'three')]  

因而,遍歷list獲取index 及 item 就更加簡單了: 
Python代碼    收藏代碼
  1. for (index, item) in enumerate(items):  
  2.     print index, item  

Python代碼    收藏代碼
  1. # compare:              # compare:  
  2. index = 0               for i in range(len(items)):  
  3. for item in items:              print i, items[i]  
  4.     print index, item  
  5.     index += 1  

不難看出,使用 enumerate 比起下面兩種方式,更加簡單,更加容易閱讀,這正是咱們想要的。 
下面是例子是如何經過 enumerate 返回迭代器: 
Python代碼    收藏代碼
  1. >>> enumerate(items)  
  2. <enumerate object at 0x011EA1C0>  
  3. >>> e = enumerate(items)  
  4. >>> e.next()  
  5. (0'zero')  
  6. >>> e.next()  
  7. (1'one')  
  8. >>> e.next()  
  9. (2'two')  
  10. >>> e.next()  
  11. (3'three')  
  12. >>> e.next()  
  13. Traceback (most recent call last):  
  14.   File "<stdin>", line 1in ?  
  15. StopIteration  



默認參數值  
這是對於一個初學者常犯的錯誤,甚至於一些高級開發人員也會遇到,由於他們並不瞭解 Python 中的 names. 
Python代碼    收藏代碼
  1. def bad_append(new_item, a_list=[]):  
  2.     a_list.append(new_item)  
  3.     return a_list  

這裏的問題是,a_list是一個空列表,默認值是在函數定義時進行初始化。所以,每次調用該函數,你會獲得不相同的默認值。嘗試了好幾回: 
Python代碼    收藏代碼
  1. >>> print bad_append('one')  
  2. ['one']  
  3. >>> print bad_append('two')  
  4. ['one''two']  

列表是可變對象,你能夠改變它們的內容。正確的方式是先得到一個默認的列表(或dict,或sets)並在運行時建立它。 
Python代碼    收藏代碼
  1. def good_append(new_item, a_list=None):  
  2.     if a_list is None:  
  3.         a_list = []  
  4.     a_list.append(new_item)  
  5.     return a_list  




判斷 True 值  
Python代碼    收藏代碼
  1. # do this:        # not this:  
  2. if x:             if x == True:  
  3.     pass              pass  

它的優點在於效率和優雅。 
判斷一個list: 
Python代碼    收藏代碼
  1. # do this:        # not this:  
  2. if items:         if len(items) != 0:  
  3.     pass              pass  
  4.   
  5.                   # and definitely not this:  
  6.                   if items != []:  
  7.                       pass  



True 值  
True和False是內置的bool類型的布爾值的實例。誰都只有其中的一個實例。 
False True
False (== 0) True (== 1)
"" (empty string)       any string but "" (" ", "anything")
0, 0.0      any number but 0 (1, 0.1, -1, 3.14)
[], (), {}, set()      any non-empty container ([0], (None,), [''])
None      almost any object that's not explicitly False


簡單比複雜好  
Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it. 
     —Brian W. Kernighan 



不要從新發明輪子  
在寫任何代碼以前, 
➔ ➔ ➔ ➔ 

原文:[urlhttp://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html][url]  javascript

(學好英文去看PEP8) html

相關文章
相關標籤/搜索