Skip to content

什么是装饰器?装饰器也是一种函数,可以接收函数作为参数,可以返回函数,接收一个函数,内部对其处理返回一个新函数,动态增强函数功能。

例如将c函数在a函数中执行,在a函数中可以选择执行或不执行c函数,也可以对c函数的结果进行二次加工。

装饰器的定义

这里以一个案例来描述装饰器是如何定义的,首先看下面代码:

python
def test(data):
    return data

需求如下:如果data='ok'则返回result is {data},如果不等于ok则返回result is failed:{data},来看装饰器的定义。

python
def check_str(func):
    def inner(*args, **kwargs):
        result = func(*args, **kwargs)
        if result == 'ok':
            return f'result is %s' % result
        else:
            return f'result is failed:%s' % result
    return inner

装饰器的使用

上面我们编写了一个装饰器,使用方法也很简单,在方法上加上@装饰器名称即可,代码如下所示:

python
def check_str(func):
    def inner(*args, **kwargs):
        result = func(*args, **kwargs)
        if result == 'ok':
            return f'result is %s' % result
        else:
            return f'result is failed:%s' % result
    return inner

@check_str
def test(data):
    return data

if __name__ == '__main__':
    result = test('no')
    print(result)

类中常用装饰器

classmethod

我的理解是,java类中有static静态方法可以直接通过类名.方法调用,而classmethod和java中的静态方法很类似。

在Python中使用@classmethod装饰后cls替代普通类函数中的self变为cls,代表操作的是类。

python
class Test(object):
    @classmethod        # self变为cls
    def add(cls, a, b):
        return a + b

print(Test.add(12, 15))  # 直接调用即可

说明:@classmethod装饰的函数无法调用普通函数,但普通函数可以调用@classmethod装饰的函数。

staticmethod

将类函数可以不经过实例化而直接被调用,被该装饰器调用的函数不许传递self或cls参数,且无法再该函数内调用其它类函数或类变量。

python
class Test(object):
    @staticmethod        # 注意没有cls或self参数
    def add(a, b):
        return a + b

print(Test.add(12, 15))  # 直接调用即可

@classmethod的区别是,@staticmethod没有cls或self参数,因此它没有办法调用类中的其他方法,常在工具类中使用。

property

当某个函数不需要传参,直接调用时,使用property装饰后,使用时可以省略括号,使用方法如下所示。

python
class Test(object):
    @property
    def hello(self):
        print("你好,我不需要参数,你可以像调用变量一样调用我")

test = Test()
test.hello         # 和调用变量一样调用函数,不需要加括号

它还有一个有趣的写法,可以像变量一样直接赋值。

python
class Test(object):
    __name = None

    @property
    def hello(self):
        print("你好,我不需要参数,你可以像调用变量一样调用我")
        return self.__name

    @hello.setter                       # 方法名.setter
    def hello(self, value):
        self.__name = value
        print(f"你好,{self.__name}")
        return self.__name

test = Test()
test.hello = '张三'
print(test.hello)

运行效果如下所示:

python
你好,张三
你好,我不需要参数,你可以像调用变量一样调用我
张三