本文根據SO上的熱門問答hidden features of python整理而成,早期有人做過類似的整理,但是內容比較舊而且比較粗糙,因此筆者在原文基礎上加入自己的一些理解,另外那些高質量的評論也引入進來了。總之,這是一篇用心之作,希望你可以喜歡。
鏈式比較操作
1 2 3 4 5 6 7 8 9 10 11 |
>>> x = 5 >>> 1 < x < 10 True >>> 10 < x < 20 False >>> x < 10 < x*10 < 100 True >>> 10 > x <= 9 True >>> 5 == x > 4 True |
你可能認為它執行的過程先是:1 < x
,返回True
,然後再比較True < 10
,當然這麼做也是返回True
,比較表示式True < 10
,因為直譯器會把True
轉換成1
,False
轉換成0
。但這裡的鏈式比較直譯器在內部並不是這樣乾的,它會把這種鏈式的比較操作轉換成:1 < x and x < 10
,不信你可以看看最後一個例子。這樣的鏈式操作本可以值得所有程式語言擁有,但是很遺憾
列舉
1 2 3 4 5 6 7 8 9 |
>>> a = ['a', 'b', 'c', 'd', 'e'] >>> for index, item in enumerate(a): print index, item ... 0 a 1 b 2 c 3 d 4 e >>> |
用enumerate包裝一個可迭代物件,可以同時使用迭代項和索引,如果你不這麼幹的話,下面有一種比較麻煩的方法:
1 2 |
for i in range(len(a)): print i, a[i] |
enumerate 還可以接收一個可選引數start,預設start等於0。enumerate(list, start=1)
,這樣index的起始值就是1
生成器物件
1 2 3 |
x=(n for n in foo if bar(n)) #foo是可迭代物件 >>> type(x) <type 'generator'> |
你可以把生成器物件賦值給x,意味著可以對x進行迭代操作:
1 2 |
for n in x: pass |
它的好處就是不需要儲存中間結果,也許你會使用(列表推倒式):
1 2 3 |
x = [n for n in foo if bar(n)] >>> type(x) <type 'list'> |
它比生成器物件能帶來更快的速度。相對地,生成器更能節省記憶體開銷,它的值是按需生成,不需要像列表推倒式一樣把整個結果儲存在記憶體中,同時它不能重新迭代,列表推倒式則不然。
iter()可接收callable引數
iter()內建函式接收的引數分為兩種,第一種是:
1 |
iter(collection)---> iterator |
引數collection必須是可迭代物件或者是序列 ,第二種是:
1 |
iter(callable, sentinel) --> iterator |
callable函式會一直被呼叫,直到它的返回結果等於sentinel,例如:
1 2 3 4 |
def seek_next_line(f): #每次讀一個字元,直到出現換行符就返回 for c in iter(lambda: f.read(1),'\n'): pass |
小心可變的預設引數
1 2 3 4 5 6 7 8 9 10 |
>>> def foo(x=[]): ... x.append(1) ... print x ... >>> foo() [1] >>> foo() [1, 1] >>> foo() [1, 1, 1] |
取而代之的是你應該使用一個標記值表示“沒有指定”來替換可變值,如:
1 2 3 4 5 6 7 8 9 |
>>> def foo(x=None): ... if x is None: ... x = [] ... x.append(1) ... print x >>> foo() [1] >>> foo() [1] |
傳送值到生成器函式在中
1 2 3 4 5 6 7 |
def mygen(): """Yield 5 until something else is passed back via send()""" a = 5 while True: f = (yield a) #yield a and possibly get f in return if f is not None: a = f #store the new value |
你可以:
1 2 3 4 5 6 7 8 9 |
>>> g = mygen() >>> g.next() 5 >>> g.next() 5 >>> g.send(7) #we send this back to the generator 7 >>> g.next() #now it will yield 7 until we send something else 7 |
如果你不喜歡使用空格縮排,那麼可以使用C語言花括號{}定義函式:
1 2 3 |
>>> from __future__ import braces #這裡的braces 指的是:curly braces(花括號) File "<stdin>", line 1 SyntaxError: not a chance |
當然這僅僅是一個玩笑,想用花括號定義函式?沒門。感興趣的還可以瞭解下:
1 |
from __future__ import barry_as_FLUFL |
不過這是python3裡面的特性,http://www.python.org/dev/peps/pep-0401/
切片操作中的步長引數
1 2 3 |
a = [1,2,3,4,5] >>> a[::2] # iterate over the whole list in 2-increments [1,3,5] |
還有一個特例:x[::-1]
,反轉列表:
1 2 |
>>> a[::-1] [5,4,3,2,1] |
有關反轉,還有兩個函式reverse、reversed,reverse是list物件的方法,沒有返回值,而reversed是內建方法,可接收的引數包括tuple、string、list、unicode,以及使用者自定義的型別,返回一個迭代器。
1 2 3 4 5 6 7 8 9 |
>>> l = range(5) >>> l [0, 1, 2, 3, 4] >>> l.reverse() >>> l [4, 3, 2, 1, 0] >>> l2 = reversed(l) >>> l2 <listreverseiterator object at 0x99faeec> |
裝飾器
裝飾器使一個函式或方法包裝在另一個函式裡頭,可以在被包裝的函式新增一些額外的功能,比如日誌,還可以對引數、返回結果進行修改。裝飾器有點類似Java中的AOP。下面這個例子是列印被裝飾的函式裡面的引數的裝飾器,
1 2 3 4 5 6 7 8 9 10 11 12 13 |
>>> def print_args(function): >>> def wrapper(*args, **kwargs): >>> print 'Arguments:', args, kwargs >>> return function(*args, **kwargs) >>> return wrapper >>> @print_args >>> def write(text): >>> print text >>> write('foo') Arguments: ('foo',) {} foo |
@是語法糖,它等價於:
1 2 3 4 |
>>> write = print_args(write) >>> write('foo') arguments: ('foo',) {} foo |
for … else語法
1 2 3 4 5 |
for i in foo: if i == 0: break else: print("i was never 0") |
else程式碼塊會在for迴圈正常結束後執行,除非遇到break(就不會執行),它等價於下面:
1 2 3 4 5 6 7 |
found = False for i in foo: if i == 0: found = True break if not found: print("i was never 0") |
不過這種語法看起來怪怪地,讓人感覺是else塊是在for語句塊沒有執行的時候執行的,很容易讓人去類比 if else 的語法,如果是把else換成finally或許更容易理解
python2.5有個__missing__
方法
dict的子類如果定義了方法__missing__(self, key)
,如果key不再dict中,那麼d[key]就會呼叫__missing__
方法,而且d[key]的返回值就是__missing__
的返回值。
1 2 3 4 5 6 7 8 9 10 |
>>> class MyDict(dict): ... def __missing__(self, key): ... self[key] = rv = [] ... return rv ... >>> m = MyDict() >>> m["foo"].append(1) >>> m["foo"].append(2) >>> dict(m) {'foo': [1, 2]} |
在collections模組下有一個叫defaultdict的dict子類,它與missing非常類似,但是對於不存在的項不需要傳遞引數。
1 2 3 4 5 6 |
>>> from collections import defaultdict >>> m = defaultdict(list) >>> m["foo"].append(1) >>> m["foo"].append(2) >>> dict(m) {'foo': [1, 2]} |
打賞支援我寫出更多好文章,謝謝!
打賞作者
打賞支援我寫出更多好文章,謝謝!