python中的装饰器decorator(中)

在上文中,我们讨论了用于修饰function的装饰器,现在我们来看用于修饰class的装饰器。首先来看一个例子,其中使用了built-in的@property @classmethod @staticmethod。@property常用于设置setter和getter。

class Student:

    def __init__(self, name,id):
        self._name = name
        self._id = id

    @property
    def id(self):
        return self._id

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, value):
        if value.isalpha():
            self._name = value

    @classmethod
    def tom(cls):
        return Student("tom",0)

    @staticmethod
    def identity():
        return "student"

在使用时,如下所示调用property修饰的方法。

>>> jack = Student("jack",1)
>>> jack.name
'jack'
>>> jack.id
1
>>> jack.name = "Jack Tony"
>>> jack.name
'jack'
>>> jack.id=2
Traceback (most recent call last):
  File "", line 1, in
AttributeError: can't set attribute

@classmethod vs @static method
1.class method第一个参数为cls,且能够获取类内部状态,通常作为一个工厂方法,返回这个类的一个对象。
2.static method仅仅为一个工具方法,不能获得类内部状态,只根据参数决定行为。

修饰类中的方法和修饰一个函数时一样的,自己定义的装饰器也可使用。另一种方式是装饰整个类

修饰整个类

我们在上文为函数写的装饰器都可以作用到类上,不过实际上等同于其作用到了类的__init__方法上。

多个decorator

函数有多个decorator,会按顺序执行。如下:

def do_twice(func):
    def do_twice_wrapper(*args,**kwargs):
        func(*args,**kwargs)

        return func(*args,**kwargs)
    return do_twice_wrapper
def debug(func):
    def debug_wrapper(*args,**kwargs):
        args_repr = [repr(a) for a in args]
        kwargs_repr = [f"{k}={v!r}"for k,v in kwargs.items() ]
        signature = ",".join(args_repr+kwargs_repr)
        print(f"calling {func.__name__}({signature})")
        value = func(*args,**kwargs)
        print(f"{func.__name__} returned {value}")
        return value

    return debug_wrapper

@do_twice
@debug
def greet(name):
    print(f"hello {name}")
greet("tom")

先@debug再@do_twice
calling greet('tom')
hello tom
greet returned None
calling greet('tom')
hello tom
greet returned None

使用带参数的decorator

比如我们要将@do_twice扩展为执行某一函数任意次数。

import functools

def repeat(num_times):
    def decorator_repeat(func):
        @functools.wraps(func)
        def wrapper_repeat(*args,**kwargs):
            for _ in range(num_times-1):
                func(*args,**kwargs)
            return func(*args,**kwargs)
        return wrapper_repeat
    return decorator_repeat

@repeat(num_times=4)
def greet(name):
    print(f"hello {name}")

改进装饰器

我们可以改进装饰器,使其既可以接受参数,也可以不接受

def repeat(_func=None,*,num_times=2):
    def decorator_repeat(func):
        @functools.wraps(func)
        def wrapper_repeat(*args,**kwargs):
            for _ in range(num_times-1):
                func(*args,**kwargs)
            return func(*args,**kwargs)
        return wrapper_repeat
    if _func is None:
        return decorator_repeat
    else:
        return decorator_repeat(_func)
@repeat
def greet(name):
    print(f"hello {name}")
#等同于,repeat参数中,_func有值
greet = repeat(greet)

@repeat(num_times=4)
def greet(name):
    print(f"hello {name}")
#等同于,repeat参数中,作为positional arguments或keywords arguments的_func没有值
tmp = repeat(num_times=4)
@tmp
def greet(name):
    print(f"hello {name}")

Original: https://www.cnblogs.com/pitaya01/p/16372374.html
Author: somelovelanguage
Title: python中的装饰器decorator(中)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/603602/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球