一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

Python裝飾器和符號@ | Hom

 CodeNutter 2016-08-04

裝飾器 Decorator

在代碼運行期間動態(tài)增加功能的方式,稱之為“裝飾器”。裝飾器本質(zhì)是高階函數(shù), 就是將函數(shù)作為參數(shù)進(jìn)行相應(yīng)運作,最后返回一個閉包代替原有函數(shù). 裝飾器本質(zhì)就是將原函數(shù)修飾為一個閉包(一個返回函數(shù)).

裝飾器在python中在函數(shù)/對象方法定義前使用@符號調(diào)用. 裝飾器可以在函數(shù)運行前進(jìn)行一些預(yù)處理, 例如檢查類型等.

@dec1
@dec2(arg1,arg2)
def test(arg):
    pass

以上代碼等于dec1(dec2(arg1,arg2)(test(arg)))

簡單的裝飾器及其運行機(jī)制

例如:

def log(func):
    def wrapper(*args, **kw):
        print 'call %s():' % func.__name__
        return func(*args, **kw)
    return wrapper

@log
def now():
    print '2015-10-26'
    return "done"
now()
# 實際調(diào)用wrapper()
#>>> call now()
#>>> 2015-10-26

裝飾器運行機(jī)制

機(jī)制就是,調(diào)用now()實際調(diào)用log(now)() (前面@寫法后,實際運行now=log(now)),也就是運行了wrapper(),并把now函數(shù)原有參數(shù)傳遞給了wrapper函數(shù). wrapper在運行時,加入了新的處理print 'call %s():' % func.__name__一句, 并運行相應(yīng)傳遞參數(shù)的func(*args,**kw)并把原有結(jié)果返回.

now=log(now) #->now=wrapper
result=now() #->wrapper()
>>>call now() #-> wrapper修飾部分
>>>2015-10-26 #-> 原函數(shù)部分執(zhí)行部分
print result
>>>done #-> 原函數(shù)的返回部分

所以裝飾器機(jī)制簡單地說就是要:

  1. 將原來函數(shù)通過裝飾器變成一個傳遞函數(shù)本身的高階函數(shù)(@log部分,now=log(now))
  2. 新的高階函數(shù)要返回一個修飾函數(shù),從而使調(diào)用原函數(shù)時實際調(diào)用該部分. (def wrapper()..return wrapper部分)
  3. 新修飾函數(shù)進(jìn)行相應(yīng)修飾處理(print語句)后,執(zhí)行原函數(shù)并返回原函數(shù)值.

傳遞參數(shù)的裝飾器

def log(text):
    def decorator(func):
        def wrapper(*args, **kw):
            print '%s %s():' % (text, func.__name__)
            return func(*args, **kw)
        return wrapper
    return decorator
@log('execute')
def now():
    print '2015-10-26'
    return "done"
now()
#>>> excute now()
#>>> 2015-10-26

裝飾器本身可以傳入?yún)?shù).不要小看這個傳入?yún)?shù), 傳入的參數(shù)因為占據(jù)了本身裝飾器的參數(shù), 所以需要新的一層裝飾器來處理原函數(shù). 上述機(jī)制:

now=log('execute')(now) #-> now=wrapper
#或者可以說f=log('execute')  -> f=decorator
#          f(now) -> decorator(now) -> wrapper
#          now=wrapper
result=now() #wrapper()

實際now=log('execute')(now)兩個參數(shù)表就是執(zhí)行了一次閉包decorator(now).執(zhí)行該閉包后返回的才是真正的裝飾器wrapper.

兩層閉包的機(jī)制可以保證傳遞參數(shù)給內(nèi)在的裝飾器wrapper.第一層將參數(shù)傳進(jìn)行生成第一層閉包對應(yīng)返回函數(shù),第二層則將該參數(shù)繼續(xù)留給真正的裝飾器閉包.

繼承原有函數(shù)信息

在以上裝飾器中, 其實質(zhì)都是now=wrapper, 此時我們要是輸出now.__name__得到的將是裝飾器wrapper的名字.可以用wrapper.__name__=func.__name__ 加在裝飾器內(nèi)部進(jìn)行原函數(shù)信息的繼承, 也可以使用functools.wraps來實現(xiàn).

import functools

def log(func):
    @functools.wraps(func)
    def wrapper(*args, **kw):
        print 'call %s():' % func.__name__
        return func(*args, **kw)
    return wrapper

對于帶參數(shù)的裝飾器, 依然將@functools.wraps(func)寫在實質(zhì)裝飾器wrapper前面.

其機(jī)制:

wrapper=functools.wraps(func)(wrapper) 
#將原函數(shù)func信息給返回函數(shù)f=functools.wraps(func), f 閉包含有相應(yīng)func信息.
#用f 返回函數(shù)來修飾wrapper, 此時實際可以將wrapper的一些信息替換為原函數(shù)

對于很復(fù)雜的體系, 需要經(jīng)常定義一些高階函數(shù)對新函數(shù)進(jìn)行一系列處理, 此時定義裝飾器就可以省很多功夫. 但缺點是初學(xué)比較難以理解, 要對OOP十分熟悉.

對象方法變對象屬性的裝飾器@property和@*.setter

該裝飾器是python內(nèi)置的,是類中一個高級用法,作用是將一個方法名變成一個對象屬性. 類需要繼承于object相應(yīng)的類.
構(gòu)建相應(yīng)@property def prop(self):return self._prop就可以直接obj.prop來將方法變成獲取對象屬性的調(diào)用形式.而相應(yīng)@prop.setter def prop(self,value): self._prop=value 就可以實現(xiàn)obj.prop=value將方法轉(zhuǎn)為對象屬性的賦值.而且好處還可以在此加入屬性的值的檢查. obj._prop只是相應(yīng)儲存的儲存地方,名字也是無限制的.
不定義setter而只定義property的話,該屬性就是只讀的不能修改的!!

例如:

class Student(object):

    @property
    def score(self):
        return self._score

    @score.setter
    def score(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')
        if value < 0 or value > 100:
            raise ValueError('score must between 0 ~ 100!')
        self._score = value

    @property
    def fail(self):
        return True if (self.score <60) else False
        # (self.score <60) and return True or return False

s = Student()
s.score = 60 # OK,實際轉(zhuǎn)化為s.set_score(60)
s.score # OK,實際轉(zhuǎn)化為s.get_score()
### 60
s.score = 9999
### Traceback (most recent call last):
###   ...
### ValueError: score must between 0 ~ 100!
s.fail
### False
s.fail=True
### Traceback (most recent call last)
### ...
### AttributeError: can't set attribute

本博文已合并到Python語法匯總中, 不再更新.


    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    亚洲国产av在线视频| 免费在线观看欧美喷水黄片| 熟女高潮一区二区三区| 亚洲最大的中文字幕在线视频 | 亚洲视频在线观看你懂的| 好吊色欧美一区二区三区顽频| 黄片在线免费看日韩欧美| 亚洲一区二区三区三州| 色综合视频一区二区观看| 亚洲妇女黄色三级视频| 特黄大片性高水多欧美一级| 国产亚洲不卡一区二区| 激情爱爱一区二区三区| 人妻露脸一区二区三区| 男女午夜视频在线观看免费| 色综合伊人天天综合网中文| 国产熟女一区二区不卡| 国产精欧美一区二区三区久久| 在线观看免费无遮挡大尺度视频| 人妻少妇系列中文字幕| 91在线播放在线播放观看| 日韩毛片视频免费观看| 中国美女草逼一级黄片视频| 色婷婷国产精品视频一区二区保健| 亚洲成人久久精品国产| 麻豆视频传媒入口在线看| 国产精品偷拍视频一区| 亚洲欧美日韩另类第一页| 丰满人妻熟妇乱又乱精品古代| 五月婷婷六月丁香狠狠| 精品亚洲av一区二区三区| 欧美性猛交内射老熟妇| 亚洲一区二区三区三区| 中文字幕欧美视频二区| av在线免费播放一区二区| 亚洲中文字幕乱码亚洲| 黑人粗大一区二区三区| 国内尹人香蕉综合在线| 亚洲内射人妻一区二区| 欧洲偷拍视频中文字幕| 99少妇偷拍视频在线|