资讯专栏INFORMATION COLUMN

python装饰器和描述器的使用总结

xietao3 / 1765人阅读

摘要:所有的描述器协议如下如果一个对象同时定义了和它叫做资料描述器。仅定义了的描述器叫非资料描述器描述器在属性访问时被自动调用。

被某些中文教程坑过,我的建议是有问题看官方文档,即使没有很详细的例子,至少不坑

装饰器

毫无疑问在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有些类似

如果被装饰的函数f带参数且有返回值

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

如果装饰器带有参数,需要多包一层,把参数调用包进去

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才会每次都调用,其它外层函数只在包装时调用一次,当然,你可以在其中声明变量,然后拿到__deco里使用。如果需要保留函数名,则在__deco上加@functools.wraps装饰器

使用 作装饰器,注意是此时相当于装饰函数,被装饰的函数会作为实例化参数,得到一个类实例,以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"
描述器

描述器在监视特定属性的时候很有用,其只在新式类中起作用。所有的描述器协议如下:

descr.__get__(self, obj, type=None) --> value
descr.__set__(self, obj, value) --> None
descr.__delete__(self, obj) --> None

如果一个对象同时定义了 __get__()__set__(),它叫做资料描述器(data descriptor)。仅定义了 __get__() 的描述器叫非资料描述器
描述器在属性访问时被自动调用。举例来说, obj.x 会在 obj 的字典中找x ,如果x定义了 __get__方法,那么 x.__get__(obj)会依据下面的优先规则被调用

调用优先级:
资料描述器 -> 实例字典 -> 非资料描述器

常用的描述器就是property了,一般都只实现了__get__的接口
先给出一个classmethod的实现和一个用于测试描述器优先级的类

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"

接下来调用

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

很明显x是资料描述器,而name不是,所以结果是

3
5
{"_data": 3, "name": "test"}

如果给classproperty加上__set__,那么就会调用被装饰的name,而不是实例化时实例字典中的name

一个property的python 实现

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__)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/37708.html

相关文章

  • Python学习之路26-函数装饰器和闭包

    摘要:初步认识装饰器函数装饰器用于在源代码中标记函数,以某种方式增强函数的行为。函数装饰器在导入模块时立即执行,而被装饰的函数只在明确调用时运行。只有涉及嵌套函数时才有闭包问题。如果想保留函数原本的属性,可以使用标准库中的装饰器。 《流畅的Python》笔记本篇将从最简单的装饰器开始,逐渐深入到闭包的概念,然后实现参数化装饰器,最后介绍标准库中常用的装饰器。 1. 初步认识装饰器 函数装饰...

    sunny5541 评论0 收藏0
  • Python中的函数装饰器和闭包

    摘要:变量查找规则在中一个变量的查找顺序是局部环境,闭包,全局,内建闭包引用了自由变量的函数。闭包的作用闭包的最大特点是可以将父函数的变量与内部函数绑定,并返回绑定变量后的函数,此时即便生成闭包的环境父函数已经释放,闭包仍然存在。 导语:本文章记录了本人在学习Python基础之函数篇的重点知识及个人心得,打算入门Python的朋友们可以来一起学习并交流。 本文重点: 1、掌握装饰器的本质、功...

    caozhijian 评论0 收藏0
  • Python中的上下文管理器和else块

    摘要:上下文管理器协议包含和两个方法。因此必要时在上下文管理器函数中使用语句防范错误。构建临时忽略指定异常的上下文管理器。这是个基类,用于定义基于类的上下文管理器。块结束时,按照后进先出的顺序调用栈中各个上下文管理器的方法。 导语:本文章记录了本人在学习Python基础之控制流程篇的重点知识及个人心得,打算入门Python的朋友们可以来一起学习并交流。 本文重点: 1、掌握if语句之外的el...

    Michael_Lin 评论0 收藏0
  • 【用故事解读 MobX 源码(四)】装饰器 和 Enhancer

    摘要:所以这是一篇插队的文章,用于去理解中的装饰器和概念。因此,该的作用就是根据入参返回具体的描述符。其次局部来看,装饰器具体应用表达式是,其函数签名和是一模一样。等装饰器语法,是和直接使用是等效等价的。 ================前言=================== 初衷:以系列故事的方式展现 MobX 源码逻辑,尽可能以易懂的方式讲解源码; 本系列文章: 《【用故事解...

    maybe_009 评论0 收藏0
  • Python装饰器、迭代器和生成器

    摘要:在学习的时候,三大名器对没有其他语言编程经验的人来说,应该算是一个小难点,本次博客就博主自己对装饰器迭代器和生成器理解进行解释。 在学习python的时候,三大名器对没有其他语言编程经验的人来说,应该算是一个小难点,本次博客就博主自己对装饰器、迭代器和生成器理解进行解释。 装饰器 什么是装饰器?装饰从字面意思来谁就是对特定的建筑物内按照一定的思路和风格进行美化的一种行为,所谓器就是工具...

    30e8336b8229 评论0 收藏0

发表评论

0条评论

xietao3

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<