日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

Python裝飾器和符號(hào)@ | Hom

 CodeNutter 2016-08-04

裝飾器 Decorator

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

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

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

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

簡(jiǎn)單的裝飾器及其運(yùn)行機(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()
# 實(shí)際調(diào)用wrapper()
#>>> call now()
#>>> 2015-10-26

裝飾器運(yùn)行機(jī)制

機(jī)制就是,調(diào)用now()實(shí)際調(diào)用log(now)() (前面@寫(xiě)法后,實(shí)際運(yùn)行now=log(now)),也就是運(yùn)行了wrapper(),并把now函數(shù)原有參數(shù)傳遞給了wrapper函數(shù). wrapper在運(yùn)行時(shí),加入了新的處理print 'call %s():' % func.__name__一句, 并運(yùn)行相應(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ī)制簡(jiǎn)單地說(shuō)就是要:

  1. 將原來(lái)函數(shù)通過(guò)裝飾器變成一個(gè)傳遞函數(shù)本身的高階函數(shù)(@log部分,now=log(now))
  2. 新的高階函數(shù)要返回一個(gè)修飾函數(shù),從而使調(diào)用原函數(shù)時(shí)實(shí)際調(diào)用該部分. (def wrapper()..return wrapper部分)
  3. 新修飾函數(shù)進(jìn)行相應(yīng)修飾處理(print語(yǔ)句)后,執(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ù).不要小看這個(gè)傳入?yún)?shù), 傳入的參數(shù)因?yàn)檎紦?jù)了本身裝飾器的參數(shù), 所以需要新的一層裝飾器來(lái)處理原函數(shù). 上述機(jī)制:

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

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

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

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

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

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

其機(jī)制:

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

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

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

該裝飾器是python內(nèi)置的,是類中一個(gè)高級(jí)用法,作用是將一個(gè)方法名變成一個(gè)對(duì)象屬性. 類需要繼承于object相應(yīng)的類.
構(gòu)建相應(yīng)@property def prop(self):return self._prop就可以直接obj.prop來(lái)將方法變成獲取對(duì)象屬性的調(diào)用形式.而相應(yīng)@prop.setter def prop(self,value): self._prop=value 就可以實(shí)現(xiàn)obj.prop=value將方法轉(zhuǎn)為對(duì)象屬性的賦值.而且好處還可以在此加入屬性的值的檢查. obj._prop只是相應(yīng)儲(chǔ)存的儲(chǔ)存地方,名字也是無(wú)限制的.
不定義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,實(shí)際轉(zhuǎn)化為s.set_score(60)
s.score # OK,實(shí)際轉(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語(yǔ)法匯總中, 不再更新.


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

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多