1. 程式人生 > >修飾符@,裝飾器(decorator),迭代器(iterator),生成器(Generator)的一些見解

修飾符@,裝飾器(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呼叫但是由於沒有其他過程,在被呼叫時只會返回值,不會有其他動作。