python裝飾器和描述器的使用總結(jié)

原文出處: quietin
被某些中文教程坑過,我的建議是有問題看官方文檔,即使沒有很詳細的例子,至少不坑

裝飾器

毫無疑問在python中用得非常多

def deco(func):
    def _deco():
        print 'before invoked'
        func()
        print 'after invoked'
    return _deco
 
@deco
def f():
    print 'f is invoked’

在f上加deco裝飾器相當于f = deco(f), 和functools.partial有些類似

如果被裝飾的函數(shù)f帶參數(shù)且有返回值

def deco(func):
    def _deco(*args, **kwargs):
        print 'before invoked'
        ret = func(*args, **kwargs)
        print 'after invoded'
        return ret
    return _deco
 
@deco
def f(a):
    print 'f is invoked'
    return a + 1

如果裝飾器帶有參數(shù),需要多包一層,把參數(shù)調(diào)用包進去

def deco(*args):
    def _deco(func):
        def __deco(*args, **kwargs):
            print 'decorator args is', args
            print 'before invoked'
            ret = func(*args, **kwargs)
            print 'after invoded'
            return ret
        return __deco
    return _deco
   
@deco('test')
def f(a):
    print 'f is invoked'
    return a + 1

只有最里面一層的__deco才會每次都調(diào)用,其它外層函數(shù)只在包裝時調(diào)用一次,當然,你可以在其中聲明變量,然后拿到__deco里使用。如果需要保留函數(shù)名,則在__deco上加@functools.wraps裝飾器

使用 類 作裝飾器,注意是類此時相當于裝飾函數(shù),被裝飾的函數(shù)會作為實例化參數(shù),得到一個類實例,以python wiki上一個做登錄檢查的代碼為例

class LoginCheck:
    def __init__(self, f):
        self._f = f
 
    def __call__(self, *args):
        Status = check_function()
        if Status is 1:
            return self._f(*args)
        else:
            return alt_function()
 
 
def check_function():
    return test
 
 
def alt_function():
    return 'Sorry - this is the forced behaviour'
 
 
@LoginCheck
def display_members_page():
    print 'This is the members page’

描述器

描述器在監(jiān)視特定屬性的時候很有用,其只在新式類中起作用。所有的描述器協(xié)議如下:

descr.get(self, obj, type=None) --> value
descr.set(self, obj, value) --> None
descr.delete(self, obj) --> None

如果一個對象同時定義了 get() 和 set(),它叫做資料描述器(data descriptor)。僅定義了 get() 的描述器叫非資料描述器
描述器在屬性訪問時被自動調(diào)用。舉例來說, obj.x 會在 obj 的字典中找x ,如果x定義了 get方法,那么 x.get(obj)會依據(jù)下面的優(yōu)先規(guī)則被調(diào)用

調(diào)用優(yōu)先級:
資料描述器 -> 實例字典 -> 非資料描述器

常用的描述器就是property了,一般都只實現(xiàn)了get的接口
先給出一個classmethod的實現(xiàn)和一個用于測試描述器優(yōu)先級的類

class classproperty(object):
    def __init__(self, func):
        self.func = func
 
    def __get__(self, instance, owner):
        return self.func(owner)
 
 
class MyClass(object):
 
    @classproperty
    def name(cls):
        return cls.__name__
 
    @property
    def x(self):
        return self._data
 
    @x.setter
    def x(self, value):
        self._data = value
 
    @x.deleter
    def x(self):
        del self._data
 
    def __init__(self, val):
        self._data = val
        self.x = 3
        self.name = ‘test'

接下來調(diào)用

s = MyClass(99)
print s.x
print s.name
print s.__dict__

很明顯x是資料描述器,而name不是,所以結(jié)果是

3
5
{‘_data’: 3, ‘name’: ‘test’}
如果給classproperty加上set,那么就會調(diào)用被裝飾的name,而不是實例化時實例字典中的name

一個property的python 實現(xiàn)

class Property(object):
    "Emulate PyProperty_Type() in Objects/descrobject.c"
 
    def __init__(self, fget=None, fset=None, fdel=None, doc=None):
        self.fget = fget
        self.fset = fset
        self.fdel = fdel
        self.__doc__ = doc
 
    def __get__(self, obj, objtype=None):
        if obj is None:
            return self
        if self.fget is None:
            raise AttributeError, "unreadable attribute"
        return self.fget(obj)
 
    def __set__(self, obj, value):
        if self.fset is None:
            raise AttributeError, "can't set attribute"
        self.fset(obj, value)
 
    def __delete__(self, obj):
        if self.fdel is None:
            raise AttributeError, "can't delete attribute"
        self.fdel(obj)
 
    def getter(self, fget):
        return type(self)(fget, self.fset, self.fdel, self.__doc__)
 
    def setter(self, fset):
        return type(self)(self.fget, fset, self.fdel, self.__doc__)
 
    def deleter(self, fdel):
        return type(self)(self.fget, self.fset, fdel, self.__doc__)

今年第六屆大會PyConChina2016,由PyChina.org發(fā)起,CPyUG/TopGeek 等社區(qū)協(xié)辦,將在2016年9月10日(上海)9月25日(深圳)10月15日(北京、杭州)地舉辦的針對Python開發(fā)者所舉辦的最盛大和權(quán)威的Python相關(guān)技術(shù)會議,由PyChina社區(qū)主辦,致力于推動各類Python相關(guān)的技術(shù)在互聯(lián)網(wǎng)、企業(yè)應(yīng)用等領(lǐng)域的研發(fā)和應(yīng)用。

您可以點擊此處
了解更多詳情,或者掃描下圖二維碼:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容