叠代器、生成器、裝飾器
1.叠代器
這裏我們先來回顧一下什麽是可叠代對象(Iterable)?
可以直接作用於for循環的對象統稱為可叠代對象,即Iterable。
# 一是集合數據類型,如list、tuple、dict、set、str等;
# 二是generator,包括生成器和帶yield的generator function。
可以被next()函數調用並不斷返回下一個值(直到沒有數據時拋出StopIteration錯誤)的對象稱為叠代器,即Iterator。
Python 叠代器(Iterators)對象在遵守叠代器協議時需要支持如下兩種方法。
__iter__(),返回叠代器對象自身。這用在 for 和 in 語句中。
__next__(),返回叠代器的下一個值。如果沒有下一個值可以返回,那麽應該拋出 StopIteration 異常。
#! /usr/bin/python #coding=utf-8 class Count(object): def __init__(self,low,high): self.low = low self.high = high def __iter__(self): return self def __next__(self): if self.low > self.high :raise StopIteration else: self.low = self.low + 1 return self.low - 1
>>> from test import Count >>> C = Count(5,10) >>> C <test.Count object at 0x7f84b94abe10> >>> for i in C : ... print (i,end = ‘ ‘) ... 5 6 7 8 9 10 >>> >>> C.__next__<bound method Count.__next__ of <test.Count object at 0x7f84b94abe10>> >>> next(C) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/home/test/python/test.py", line 13, in __next__ raise StopIteration StopIteration >>> C = Count(5,6) >>> next(C) 5 >>> next(C) 6 >>> next(C) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/home/test/python/test.py", line 13, in __next__ raise StopIteration StopIteration
2.生成器
我們常說的生成器,
就是帶有 yield
的函數
>>> def counter_generator(low, high): ... while low <= high: ... yield low ... low += 1 ... >>> for i in counter_generator(5,10): ... print(i, end=‘ ‘) ... 5 6 7 8 9 10
在 While 循環中,每當執行到 yield 語句時,返回變量 low 的值並且生成器狀態轉為掛起。在下一次調用生成器時,生成器從之前凍結的地方恢復執行然後變量 low 的值增一。生成器繼續 while 循環並且再次來到 yield 語句...
當你調用生成器函數時它返回一個生成器對象。如果你把這個對象傳入 dir() 函數,你會在返回的結果中找到 __iter__ 和 __next__ 兩個方法名。
我們通常使用生成器進行惰性求值。這樣使用生成器是處理大數據的好方法。如果你不想在內存中加載所有數據,你可以使用生成器,一次只傳遞給你一部分數據。
os.path.walk() 函數是最典型的這樣的例子,它使用一個回調函數和當前的 os.walk 生成器。使用生成器實現節約內存。
我們可以使用生成器產生無限多的值。以下是一個這樣的例子。
>>> def infinite_generator(start=0): ... while True: ... yield start ... start += 1 ... >>> for num in infinite_generator(4): ... print(num, end=‘ ‘) ... if num > 20: ... break ... 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
生成器是一定不能重復循環的
3. 閉包
閉包(Closures)是由另外一個函數返回的函數。我們使用閉包去除重復代碼。在下面的例子中我們創建了一個簡單的閉包來對數字求和
>>> def add_number(num): ... def adder(number): ... #adder 是一個閉包 ... return num + number ... return adder ... >>> a_10 = add_number(10) >>> a_10(21) 31 >>> a_10(34) 44 >>> a_5 = add_number(5) >>> a_5(3) 8
adder 是一個閉包,把一個給定的數字與預定義的一個數字相加。
4.裝飾器
裝飾器(Decorators)用來給一些對象動態的添加一些新的行為,我們使用過的閉包也是這樣的。
裝飾器其實就是一個閉包,把一個函數當做參數然後返回一個替代版函數
>>> def my_decorator(func): ... def wrapper(*args, **kwargs): ... print("Before call") ... result = func(*args, **kwargs) ... print("After call") ... return result ... return wrapper ... >>> @my_decorator ... def add(a, b): ... #我們的求和函數 ... return a + b ... >>> add(1, 3) Before call After call 4
定義函數的時候使用了*,意味著那些通過位置傳遞的參數將會被放在帶有*前綴的變量中, 所以:
def one(*args): print args # 1 one() () one(1, 2, 3) (1, 2, 3) def two(x, y, *args): # 2 print x, y, args two(‘a‘, ‘b‘, ‘c‘) a b (‘c‘,)
第一個函數one只是簡單地講任何傳遞過來的位置參數全部打印出來而已,你們能夠看到,在代碼#1處我們只是引用了函數內的變量args, *args僅僅只是用在函數定義的時候用來表示位置參數應該存儲在變量args裏面。Python允許我們制定一些參數並且通過args捕獲其他所有剩余的未被捕捉的位置參數,就像#2處所示的那樣。
*操作符在函數被調用的時候也能使用。意義基本是一樣的。當調用一個函數的時候,一個用*標誌的變量意思是變量裏面的內容需要被提取出來然後當做位置參數被使用。同樣的,來看個例子:
def add(x, y): return x + y lst = [1,2] add(lst[0], lst[1]) # 1 3 add(*lst) # 2 3
#1處的代碼和#2處的代碼所做的事情其實是一樣的,在#2處,python為我們所做的事其實也可以手動完成。這也不是什麽壞事,*args要麽是表示調用方法大的時候額外的參數可以從一個可叠代列表中取得,要麽就是定義方法的時候標誌這個方法能夠接受任意的位置參數。
接下來提到的**會稍多更復雜一點,**代表著鍵值對的餐宿字典,和*所代表的意義相差無幾,也很簡單對不對:
def foo(**kwargs): print kwargs foo() {} foo(x=1, y=2) {‘y‘: 2, ‘x‘: 1}
當我們定義一個函數的時候,我們能夠用**kwargs來表明,所有未被捕獲的關鍵字參數都應該存儲在kwargs的字典中。如前所訴,argshe kwargs並不是python語法的一部分,但在定義函數的時候,使用這樣的變量名算是一個不成文的約定。和*一樣,我們同樣可以在定義或者調用函數的時候使用**。
dct = {‘x‘: 1, ‘y‘: 2} def bar(x, y): return x + y bar(**dct) 3
更加通用的裝飾器
def logger(func): def inner(*args, **kwargs): #1 print "Arguments were: %s, %s" % (args, kwargs) return func(*args, **kwargs) #2 return inner
@logger def foo1(x, y=1): return x * y @logger def foo2(): return 2 foo1(5, 4) Arguments were: (5, 4), {} 20 foo1(1) Arguments were: (1,), {} 1 foo2() Arguments were: (), {} 2
請註意我們的函數inner,它能夠接受任意數量和類型的參數並把它們傳遞給被包裝的方法,這讓我們能夠用這個裝飾器來裝飾任何方法。
http://python.jobbole.com/81683/
叠代器、生成器、裝飾器