python 装饰器 decorator,描述器 descriptor,@property属性,@wrap,update_wrapper

装饰器 decorator

官方文档定义

decorator -- 装饰器 返回值为另一个函数的函数,通常使用 @wrapper 语法形式来进行函数变换。装饰
器的常见例子包括 classmethod() 和 staticmethod()。
装饰器语法只是一种语法糖,以下两个函数定义在语义上完全等价:

def f(...):
... 
f = staticmethod(f)
@staticmethod
def f(...):
... 

同的样概念也适用于类,但通常较少这样使用。有关装饰器的详情可参见 函数定义和 类定义的文
档。

相关知识点

  • 函数,类都是对象

函数可以当做参数传递或返回值

  • 闭包

内部函数使用外部函数定义的变量
返回内部函数对象在外边调用

参考范例

  • 不带参数的装饰器
import time
def showtime(func):
    def wrapper():
        start_time = time.time()
        func()
        end_time = time.time()
        print('spend is {}'.format(end_time - start_time))

    return wrapper

@showtime  #foo = showtime(foo)
def foo():
    print('foo..')
    time.sleep(3)

@showtime #doo = showtime(doo)
def doo():
    print('doo..')
    time.sleep(2)

foo()
doo()
  • 被装饰的函数带参数
import time
def showtime(func):
    def wrapper(a, b):
        start_time = time.time()
        func(a,b)
        end_time = time.time()
        print('spend is {}'.format(end_time - start_time))

    return wrapper

@showtime #add = showtime(add)
def add(a, b):
    print(a+b)
    time.sleep(1)

@showtime #sub = showtime(sub)
def sub(a,b):
    print(a-b)
    time.sleep(1)

add(5,4)
sub(3,2)
  • 带参数的装饰器
import time
def time_logger(flag = 0):
    def showtime(func):
        def wrapper(a, b):
            start_time = time.time()
            func(a,b)
            end_time = time.time()
            print('spend is {}'.format(end_time - start_time))

            if flag:
                print('将此操作保留至日志')

        return wrapper

    return showtime

@time_logger(2)  #得到闭包函数showtime,add = showtime(add)
def add(a, b):
    print(a+b)
    time.sleep(1)

add(3,4)
  • 定义类装饰器装饰函数
import time
class Foo(object):
    def __init__(self, func):
        self._func = func

    def __call__(self):
        start_time = time.time()
        self._func()
        end_time = time.time()
        print('spend is {}'.format(end_time - start_time))

@Foo  #bar = Foo(bar)
def bar():
    print('bar..')
    time.sleep(2)

bar()
  • 装饰器装饰类
# 定义一个装饰器
def decorator(cls):
    print("这里可以写被装饰类新增的功能") 
    return cls


# 定义一个类 A,并使用decorator装饰器装饰
@decorator # 装饰器的本质 A = decorator(A),装饰器返回类本身,还是之前的类,只是在返回之前增加了额外的功能
class A(object):
    def __init__(self):
        pass

    def test(self):
        print("test")

描述器 descriptor

官方文档定义

descriptor -- 描述器 任何定义了 get(), set() 或 delete() 方法的对象。当一个类属
性为描述器时,它的特殊绑定行为就会在属性查找时被触发。通常情况下,使用 a.b 来获取、设置
或删除一个属性时会在 a 的类字典中查找名称为 b 的对象,但如果 b 是一个描述器,则会调用对应
的描述器方法。理解描述器的概念是更深层次理解 Python 的关键,因为这是许多重要特性的基础,
包括函数、方法、属性、类方法、静态方法以及对超类的引用等等。
有关描述符的方法的详情可参看 descriptors。

@property属性

@property是个描述器 descriptor

参考源码

class property(object):
    """
    Property attribute.
    
      fget
        function to be used for getting an attribute value
      fset
        function to be used for setting an attribute value
      fdel
        function to be used for del'ing an attribute
      doc
        docstring
    
    Typical use is to define a managed attribute x:
    
    class C(object):
        def getx(self): return self._x
        def setx(self, value): self._x = value
        def delx(self): del self._x
        x = property(getx, setx, delx, "I'm the 'x' property.")
    
    Decorators make defining new properties or modifying existing ones easy:
    
    class C(object):
        @property
        def x(self):
            "I am the 'x' property."
            return self._x
        @x.setter
        def x(self, value):
            self._x = value
        @x.deleter
        def x(self):
            del self._x
    """
    ...

@wrap,update_wrapper

修改被装饰函数的元信息

WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__qualname__', '__doc__',
                       '__annotations__')

参考源码

################################################################################
### update_wrapper() and wraps() decorator
################################################################################

# update_wrapper() and wraps() are tools to help write
# wrapper functions that can handle naive introspection

WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__qualname__', '__doc__',
                       '__annotations__')
WRAPPER_UPDATES = ('__dict__',)
def update_wrapper(wrapper,
                   wrapped,
                   assigned = WRAPPER_ASSIGNMENTS,
                   updated = WRAPPER_UPDATES):
    """Update a wrapper function to look like the wrapped function

       wrapper is the function to be updated
       wrapped is the original function
       assigned is a tuple naming the attributes assigned directly
       from the wrapped function to the wrapper function (defaults to
       functools.WRAPPER_ASSIGNMENTS)
       updated is a tuple naming the attributes of the wrapper that
       are updated with the corresponding attribute from the wrapped
       function (defaults to functools.WRAPPER_UPDATES)
    """
    for attr in assigned:
        try:
            value = getattr(wrapped, attr)
        except AttributeError:
            pass
        else:
            setattr(wrapper, attr, value)
    for attr in updated:
        getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
    # Issue #17482: set __wrapped__ last so we don't inadvertently copy it
    # from the wrapped function when updating __dict__
    wrapper.__wrapped__ = wrapped
    # Return the wrapper so this can be used as a decorator via partial()
    return wrapper

def wraps(wrapped,
          assigned = WRAPPER_ASSIGNMENTS,
          updated = WRAPPER_UPDATES):
    """Decorator factory to apply update_wrapper() to a wrapper function

       Returns a decorator that invokes update_wrapper() with the decorated
       function as the wrapper argument and the arguments to wraps() as the
       remaining arguments. Default arguments are as for update_wrapper().
       This is a convenience function to simplify applying partial() to
       update_wrapper().
    """
    return partial(update_wrapper, wrapped=wrapped,
                   assigned=assigned, updated=updated)

参考资源链接

python3 装饰器全解
Python 使用装饰器装饰类
Python@property详解及底层实现介绍

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容