圍繞一門語言,學習它的文化精髓,能讓你成為一名更優秀的程序員。如果你還沒讀過Python之禪(Zen of Python) ,那么打開Python的命令提示符輸入import this,列表中的每一項你都可以在這里找到相對應的例子。
吸引我注意力的一條是:
優雅勝于丑陋 (Beautiful is better than ugly)
看下面例子:
一個帶有數字參數的list函數其功能是返回參數中的奇數可以分開寫:
1
2
3
4
5
6
|
#----------------------------------------------------------------------- halve_evens_only = lambda nums: map ( lambda i: i / 2 ,\ filter ( lambda i: not i % 2 , nums)) #----------------------------------------------------------------------- def halve_evens_only(nums): return [i / 2 for i in nums if not i % 2 ] |
記住Python中那些非常簡單的事
兩個變量的交換:
1
|
a, b = b, a |
參數在切片操作中的步驟,如:
1
2
3
|
a = [ 1 , 2 , 3 , 4 , 5 ] >>> a[:: 2 ] # 以步長為2的增量迭代整個list對象 [ 1 , 3 , 5 ] |
一個特殊的例子 `x[::-1]`用來反轉x的實用語法。
1
2
|
>>> a[:: - 1 ] [ 5 , 4 , 3 , 2 , 1 ] |
不要用可變對象作為默認參數值(Don't use mutable as defaults)
1
2
3
4
|
def function(x, l = []): # 不要這么干 def function(x, l = None ): # 更好的一種方式 if l is None : l = [] |
使用iteritems而不是items
iteriterms 使用的是 generators,所以當迭代很大的序列是此方法更好
1
2
3
4
5
|
d = { 1 : "1" , 2 : "2" , 3 : "3" } for key, val in d.items() # 調用items()后會構建一個完整的list對象 for key, val in d.iteritems() # 只有在迭代時每請求一次才生成一個值 |
此情景和range與xrange的關系相似。
使用isinstance 而不是type
不要這樣做:
1
2
3
|
if type (s) = = type (""): ... if type (seq) = = list or \ type (seq) = = tuple : ... |
應該是這樣:
1
2
|
if isinstance (s, basestring ): ... if isinstance (seq, ( list , tuple )): ... |
至于為什么這樣做,看這里:http://stackoverflow.com/a/1549854/504262
需要注意的是這里使用basestring而不是str是因為你可能會用一個unicode對象去檢查是否為string,例如:
1
2
3
4
5
|
>>> a = u 'aaaa' >>> print isinstance (a, basestring ) True >>> print isinstance (a, str ) False |
因為在Python中3.0以下的版本存在兩種字符串類型str和unicode
學習各種集合(learn the various collections)
python有各種各樣的容器數據類型,在特定情況下選擇python內建的容器如:list和dict。通常更多像如下方式使用:
1
2
3
4
5
6
|
freqs = {} for c in "abracadabra" : try : freqs[c] + = 1 except : freqs[c] = 1 |
一種更好的方案如下:
1
2
3
|
freqs = {} for c in "abracadabra" : freqs[c] = freqs.get(c, 0 ) + 1 |
一種更好的選擇 collection類型defautdict:
1
2
3
4
|
from collections import defaultdict freqs = defaultdict( int ) for c in "abracadabra" : freqs[c] + = 1 |
其它集合
1
2
3
4
5
|
namedtuple() # 用指定的域創建元組子類的工廠函數 deque # 類似list的容器,快速追加以及刪除在序列的兩端 Counter # 統計哈希表的dict子類 OrderedDict # 記錄實體添加順序的dict子類 defaultdict # 調用工廠方法為key提供缺省值的dict子類 |
當創建類時Python的魔術方法:
1
2
3
4
5
6
|
__eq__( self , other) # 定義相等操作的行為, ==. __ne__( self , other) # 定義不相等操作的行為, !=. __lt__( self , other) #定義小于操作的行為, <. __gt__( self , other) #定義不大于操作的行為, >. __le__( self , other) #定義小于等于操作的行為, <=. __ge__( self , other) #定義大于等于操作的行為, >=. |
條件賦值
1
|
x = 3 if (y = = 1 ) else 2 |
表達式請起來恰恰像:如果y等于1就把3賦值給x,否則把2賦值給x,當然同樣可以使用鏈式條件賦值如果你還有更復雜的條件的話。
1
|
x = 3 if (y = = 1 ) else 2 if (y = = - 1 ) else 1 |
然而到了某個特定的點,它就有點兒過分了。
記住,你可以在任何表達式中使用if-else例如:
1
|
(func1 if y = = 1 else func2)(arg1, arg2) |
func1將被調用如果y等于1的話,反之func2被調用。兩種情況下,arg1和arg2兩個參數都將附帶在相應的函數中。
類似地,下面這個表達式同樣是正確的
1
|
x = (class1 if y = = 1 else class2)(arg1, arg2) |
class1和class2是兩個類
在有必要的時侯使用Ellipsis
創建類時,你可以使用__getitem__,讓你的類像字典一個工作,拿下面這個類舉例來說:
1
2
3
4
5
6
7
8
|
class MyClass( object ): def __init__( self , a, b, c, d): self .a, self .b, self .c, self .d = a, b, c, d def __getitem__( self , item): return getattr ( self , item) x = MyClass( 10 , 12 , 22 , 14 ) |
因為有了__getitem__,你就能夠通過對象x的x[‘a']獲取a的值,這應該是公認的事實。
這個對象通常用于繼承Python的切片(slicing) (http://docs.python.org/library/stdtypes.html#bltin-ellipsis-object),如果添加如下語句:
1
2
3
4
5
|
def __getitem__( self , item): if item is Ellipsis: return [ self .a, self .b, self .c, self .d] else : return getattr ( self , item) |
我們就可以使用x[…]獲取的包含所有項的序列
1
2
3
|
>>> x = MyClass( 11 , 34 , 23 , 12 ) >>> x[...] [ 11 , 34 , 23 , 12 ] |