修飾符@,裝飾器(decorator),迭代器(iterator),生成器(Generator)的一些見解
這三個方法,在Python裡的使用並不多,然而,各大網際網路公司還特別喜歡考這一方面的。以前因為不常用,有些忽視了這幾個方法,碰了幾次壁後,決心好好整理一番這三個方法(以下程式碼均在python3.6的環境下實驗):
1.修飾符@和裝飾器
很多地方說的修飾符,裝飾器其實是同一個東西。
'@' 用做函式的修飾符。
修飾符出現在函式的前一行。
一個修飾符就是一個函式,它將被修飾的函式作為引數,並返回修飾後的同名函式,借用一個例子如下。
def square_sum(fn): def square(*args): print ("1---", args) n = args[0] # return n*(n-1)*(2*n-1)/6 print ("2==", n*(n-1)*(2*n-1)/6) print (fn.__name__) fn(n*(n-1)*(2*n-1)/6) print ("*"*15) return fn(n*(n-1)*(2*n-1)/6) return square @square_sum def sum_a(a): print ("3=", a) sum_a(10)
結果如下:
1--- (10,)
2== 285.0
sum_a
3= 285.0
***************
3= 285.0
可以看到,在sum_a(10)的時候,引數並不是傳給了函式sum_a,而是給了修飾符@square_sum,而引數fn代表的"__name__"也成了要與修飾的函式重名。而square_sum(fn)的返回結果,才是sum_a()真正的輸入引數。
2.裝飾器(decorator)裡的靜態方法和類方法
@staticmethod是靜態方法,在使用的時候可以不需要self引數,直接呼叫。
class Foo: @staticmethod #裝飾器,靜態方法 def spam(x,y,z): print(x,y,z) print(type(Foo.spam)) #型別就是class function Foo.spam(1,2,3) #傳參 f1=Foo() f1.spam(3,3,3) #傳參
<class 'function'>
1 2 3
3 3 3
這裡第一次傳參的時候,可以看到,並沒有給類class Foo進行例項化物件,就直接呼叫了裡面的方法。第二次傳參的時候,才進行類的例項化物件。
classmethod 修飾符對應的函式不需要例項化,不需要 self 引數,但第一個引數需要是表示自身類的 cls 引數,可以來呼叫類的屬性,類的方法,例項化物件等。
class A(object):
bar = 1
def func1(self):
print ('foo')
@classmethod #類方法
def func2(cls):
print ('func2')
print (cls.bar)
cls().func1() # classmethod可以直接呼叫類裡的 foo 方法
A.func2() # 不需要例項化,
func2
1
foo
類方法定義後,可以獲取類裡的屬性,物件,成員等。
3.iter迭代器
it = iter([1,2,3])
print(next(it))
print(next(it))
#print(next(it))
#print(next(it))
for i in it:
print(i)
1
2
3
會發現以上程式碼使用next()註釋掉幾行,仍然結果是1,2,3,並沒有變化,next()方法返回下一個值,然而調用了一次next後,相應的it迭代器裡面的值也減少了。for迴圈裡的值也相應的減少了。最後在用next()的時候,如果沒有返回值,會引發一個StopIteration的異常。
最後說一下,iter的實用價值在於:如果列表過大,如果有100萬個詞甚至更大,組成的列表,一次載入整個列表,會導致記憶體不足,在使用的時候,就要考慮使用迭代器,降低列表對記憶體的佔用。
4.yield生成器
任何包含yield語句的函式都被稱為生成器。
def power(values):
for value in values:
print ("powing %s" % value)
yield value
def add(values):
for value in values:
if value % 2 == 0:
yield value + 3
else:
yield value + 2
elements = [1, 4, 7]
add(power(elements))
for i in add(power(elements)):
print(i)
powing 1
3
powing 4
7
powing 7
9
生成器是以函式的方式被建立,在使用的時候只有在被next()呼叫或者for迴圈呼叫時,裡面的過程才會被執行,如同上面的例子只是單純呼叫add這個物件時,add裡面的過程沒有被執行哦
迭代器同樣可以被for和next呼叫但是由於沒有其他過程,在被呼叫時只會返回值,不會有其他動作。