Python_裝飾器,迭代器,生成器

●裝飾器


裝飾器用來增強 函數 的功能 但是不改變其原有的結構與功能 。 在代碼運行期間 動態的添加功能 稱爲 裝飾器。

如何理解裝飾器?

1.不改變函數結構,即不對函數本身結構體做任何修改;
2.增強函數功能;比如起跳時能帶一道彩虹,那麼能構造彩虹功能即可以定義爲起跳函數的裝飾器,並不影響起跳這個函數;
3.本質上,裝飾器就是一個返回函數的高階函數。

下面我們定義一個起跳函數

def jump():
    print('我正在蹦躂')

定義一個裝飾器

def rainbow(main):
    def make_rainbow(*args,**kwargs):
        print('你被掛上了彩虹:%s'%(main.__name__))
        return main(*args,**kwargs)
    return make_rainbow 

看這個裝飾器(decorator),因爲rainbow是一個裝飾器 ,所以他是接受一個函數作爲參數(main)的。
藉助Python的@語法,把decorator置於函數的定義處:

@rainbow
def jump():
    print('我正在蹦躂')

執行jump:

if __name__ == '__main__':
    jump()

這裏寫圖片描述
我們從結果上來看,是先執行 裝飾器 然後用才執行主函數 那麼具體步驟是怎樣的呢?

把@raninbow放到jump()函數的定義處,相當於執行了語句:jump=raninbow(jump);
那麼 raninbow 返回的是一個新函數 jump() ,那麼現在同名的now變量指向了新的函數 ,在rainbow()函數內,首先打印日誌,再緊接着調用原始函數 。

import json
'''
裝飾器
'''
def guess_with(func):
    def rooftop_status():
        result = func()
        print("天台見")
        return result
    return rooftop_status

@guess_with
def german_team():
    print("德國必勝")

# german_team()
'''函數名可以賦值給變量'''
def a(name):
    print("我是{}!慌得一批!".format(name))
a("梅西")
y = a
y("樂福")

'''高階函數
    高階函數滿足其一即爲高階函數:
    a.可以接受函數名作爲實參;
    b.返回值中可以包含函數名
    '''
r = map(lambda x:x*3, [3,3,4,5,6])
for i in r:
    print("當前天台人數:", i)

# 定義一個可以返回函數的函數 也就是高階函數
def f(l):
    return map(lambda x: x*10,l)
aaa = f([10,22,333])
for i in aaa:
    print("已跳天台人數:", i)

'''有了以上的兩個概念 實現一個類似的裝飾器'''

def status(func):  #接受一個 函數名參數 並返回了該函數名 並不會修改原函數 只是增加了一個本身帶有的表動
    print('慌得一批!')
    return func
def name():
    print("我是勒布朗")

'''在調用時 這裏有個缺陷 就是函數調用方式改變了;即不是原本的name,而是 t 
    那麼改成 name = status(name) 不就可以了?但是每次使用這樣的裝飾器 都要寫這一句
    那麼簡化一下 python提供了一個語法糖 @  在每個被裝飾的函數上使用這個@即爲代替name=status(name)
'''
name = status(name) #
name()

def status(func):
    print('慌得一批')
    return func

@status
def name():
    print('LBJ')

name()
"""
    裝飾器的工作原理:
    ①構建一個高階函數 參數爲函數 返回的也是函數
    ②再利用語法糖@ 簡化賦值操作
"""
def guess_win(func):
    def rooftop_status():
        result = func()
        print('天台已滿,請排隊')
        return result
    return rooftop_status
@guess_win
def german_team():
    print('德國必勝')
    return '贏了會所嫩模!輸了下海乾活!'
x = german_team()
print(x)
"""
    裝飾器本事就是函數,其參數是另一個函數(被裝飾的函數)
    裝飾器通常會額外處理被裝飾的函數,然後把它返回,或者將替換成另外一個函數或可調用對象
"""

●迭代器


迭代器 :可以被next()函數調用並不斷返回下一個值的對象稱爲迭代器:Iterator。實現 迭代迭代器協議的 容器對象
注:
訪問者無需關注迭代器內部 僅需要通過 next() 方法 去取下一個內容
不能隨機訪問 集合中的某個值 只能從頭到尾訪問
訪問到一半時 不能往回退
便於循環較大的數據集合 節省內存

a  = iter([1,2,3,4,5,555,666])
>>> a = iter([1,2,3,4,56,77])
>>> a.__next__()
1
>>> a.__next__()
2
>>> a.__next__()
3
>>> a.__next__()
4
>>> a.__next__()
56
>>> a.__next__()
77

●生成器


生成器 :一個函數調用時返回一個迭代器,那這個函數就叫做生成器(generator);
如果函數中包含yield語法,那這個函數就會變成生成器。

>>> def odd():
...     print 'step 1'
...     yield 1
...     print 'step 2'
...     yield 3
...     print 'step 3'
...     yield 5
...
>>> o = odd()
>>> o.next()
step 1
1
>>> o.next()
step 2
3
>>> o.next()
step 3
5
>>> o.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

generator保存的是算法,每次調用next(),就計算出下一個元素的值,直到計算到最後一個元素,沒有更多的元素時,拋出StopIteration的錯誤。
判斷一個函數是否是一個特殊的 generator 函數?可以利用 isgeneratorfunction 判斷:
下面使用 yield 書寫一個斐波那契 函數:

#1.常規版本
def fab(max):
    n,a,b = 0,0,1
    while n <max:
        print(b)
        a,b,=b,a+b
        n =n+1
>>> from inspect import isgeneratorfunction 
>>> isgeneratorfunction(fab) 
False
#2.yield版本
def fab(max):
    n,a,b = 0,0,1
    while n <max:
        yield b
        a,b,=b,a+b
        n =n+1
>>> isgeneratorfunction(fab) 
False

yield 的好處是顯而易見的,把一個函數改寫爲一個 generator 就獲得了迭代能力,比起用類的實例保存狀態來計算下一個 next() 的值,不僅代碼簡潔,而且執行流程異常清晰;
如:
這裏寫圖片描述
參考自:https://www.ibm.com/developerworks/cn/opensource/os-cn-python-yield/
https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章