python装饰器总结

装饰器的使用方法

装饰器是什么?当程序函数写好之后业务做了修改,此时需要更改原来的函数。为了简化此操作,即不再改变原函数,python提供了装饰器机制。

同时也可以避免大量的代码重复,例如有三个函数f1,f2,f3分别需要计算三个函数的执行时间,如下所示:

from time import time, sleep
def f2():
    start = time()
    for i in range(100):
        eval('1 + 1 * 2')
    sleep(1)
    end = time()
    print(f'f2执行时间为{end - start}')


def f3():
    start = time()
    for i in range(50):
        eval('2 + 1 / 3')
    sleep(3)
    end = time()
    print(f'f3执行时间为{end - start}')


def f4():
    start = time()
    for i in range(25):
        eval('4 + 1 + 5')
    sleep(2)
    end = time()
    print(f'f4执行时间为{end - start}')


if __name__ == '__main__':
    f2()
    f3()
    f4()

需要将代码段

start = time()
...
end = time()
print(f'执行时间为{end - start}')

写三次,当函数很多时,显然会降低编码效率,因此我们引入了装饰器,顾名思义,就是对一个函数进行“装饰”。

无参数的装饰器
# coding=utf-8


def decorate(func):
    def wrapper():
        print(f'函数{func.__name__}开始执行...')
        func()
        print(f'函数{func.__name__}执行完毕')
    return wrapper


@decorate
def f1():
    print('计算1+1的结果')


@decorate
def f2():
    print('计算2+2的结果')


f1()
f2()

在函数f1执行时,会把f1函数作为参数传到装饰器decorate中,然后返回decorate中的函数wrapper,实际执行的是wrapper函数(wrapper函数中的func函数会执行f1函数)

以上代码的输出结果为:

函数f1开始执行...
计算1+1的结果
函数f1执行完毕
函数f2开始执行...
计算2+2的结果
函数f2执行完毕

到此,我们可以通过装饰器修改以上计算运行时间的代码段

# coding=utf-8
from time import time, sleep


def decorate(func):
    def wrapper():
        start = time()
        func()
        end = time()
        print(f'{func.__name__}执行时间为{end - start}')
    return wrapper


@decorate
def f2():
    for i in range(100):
        eval('1 + 1 * 2')
    sleep(1)


@decorate
def f3():
    for i in range(50):
        eval('2 + 1 / 3')
    sleep(3)


@decorate
def f4():
    for i in range(25):
        eval('4 + 1 + 5')
    sleep(2)


if __name__ == '__main__':
    f2()
    f3()
    f4()

以上代码的执行结果依然为:

f2执行时间为1.0111098289489746
f3执行时间为3.00311541557312
f4执行时间为2.0160653591156006
带固定参数函数的装饰器
# coding=utf-8
def decorate(func):
    def wrapper(number):
        print(f'{func.__name__}函数开始执行...')
        func(number)
        print(f'number的值为{number}')
        print(f'{func.__name__}函数运行结束\n')
    return wrapper


@decorate
def f1(number):
    print(f'计算{number}+{number}的值...')


@decorate
def f2(number):
    print(f'计算{number}*{number}+{number}的值...')


f1(1)
f2(2)

输出结果为

f1函数开始执行...
计算1+1的值...
number的值为1
f1函数运行结束

f2函数开始执行...
计算2*2+2的值...
number的值为2
f2函数运行结束
带不定参数函数的装饰器
# coding=utf-8
def decorate(func):
    def wrapper(*args, **kwargs):
        print(f'{func.__name__}函数开始执行...')
        func(*args, **kwargs)
        print(f'{func.__name__}函数运行结束\n')
    return wrapper


@decorate
def f1(number1, number2):
    print(f'计算{number1}+{number2}的值...')


@decorate
def f2(number1, number2, number3):
    print(f'计算{number1}*{number2}+{number3}的值...')


f1(1, 2)
f2(2, 3, 4)

输出结果为

f1函数开始执行...
计算1+2的值...
f1函数运行结束

f2函数开始执行...
计算2*3+4的值...
f2函数运行结束
带参数的装饰器
# coding=utf-8


def decorate(style):
    def wrapper(func):
        def wrapped(*args, **kwargs):
            print(f"装饰器的参数为{style}")
            print(f"{func.__name__}函数开始执行...")
            func(*args, **kwargs)
            print(f'{func.__name__}函数执行完毕\n')
        return wrapped
    return wrapper


@decorate(style='invis')
def f1(num, cnt):
    print(f"num={num}, cnt={cnt}")


@decorate(style='bold')
def f2(x, y, z):
    print(f"x={x}, y={y}, z={z}")


f1(1, 2)
f2(3, 4, 5)

输出结果为

装饰器的参数为invis
f1函数开始执行...
num=1, cnt=2
f1函数执行完毕

装饰器的参数为bold
f2函数开始执行...
x=3, y=4, z=5
f2函数执行完毕
类作为装饰器

类作为装饰器时要实现类的__init__方法和__call__方法

不带参数

不带参数的装饰器中的__init__方法要传入函数

# coding=utf-8


class Decorate:

    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print(f'{self.func.__name__}函数开始执行...')
        self.func(*args, **kwargs)
        print(f'{self.func.__name__}函数执行完毕\n')


@Decorate
def f1(x, y):
    print(f"x={x}, y={y}")


@Decorate
def f2(x, y, z):
    print(f'x={x}, y={y}, z={z}')


f1(1, 2)
f2(3, 4, 5)

输出结果为

f1函数开始执行...
x=1, y=2
f1函数执行完毕

f2函数开始执行...
x=3, y=4, z=5
f2函数执行完毕
带参数

带参数的装饰器中的__init__方法传入参数,__call__方法传入函数

# coding=utf-8


class Decorate:

    def __init__(self, style):
        self.style = style

    def __call__(self, func):
        def wrapper(*args, **kwargs):
            print(f'装饰器参数值为{self.style}')
            print(f'{func.__name__}函数开始执行...')
            func(*args, **kwargs)
            print(f'{func.__name__}函数执行完毕\n')
        return wrapper


@Decorate(style='invis')
def f1(x, y):
    print(f"x={x}, y={y}")


@Decorate(style='bold')
def f2(x, y, z):
    print(f'x={x}, y={y}, z={z}')


f1(1, 2)
f2(3, 4, 5)

输出结果为

装饰器参数值为invis
f1函数开始执行...
x=1, y=2
f1函数执行完毕

装饰器参数值为bold
f2函数开始执行...
x=3, y=4, z=5
f2函数执行完毕
类内的成员函数作为类内函数的装饰器使用
# coding=utf-8


class Test:

    def __init__(self, num):
        self.num = num

    def decorate(func):
        def wrapper(self, *args, **kwargs):
            print(f'{func.__name__}函数开始执行...')
            func(self, *args, **kwargs)
            print(f'{func.__name__}函数执行完毕\n')
        return wrapper

    @decorate
    def standard_output(self, x, y, z):
        print(f'x={x}, y={y}, z={z}')


s = Test(2)
s.standard_output(3, 4, 5)

输出结果为

standard_output函数开始执行...
x=3, y=4, z=5
standard_output函数执行完毕
类的成员函数作为类外函数的装饰器
# coding=utf-8


class Test:

    def __init__(self, num):
        self.num = num

    def decorate(func):
        def wrapper(*args, **kwargs):
            print(f'{func.__name__}函数开始执行...')
            func(*args, **kwargs)
            print(f'{func.__name__}函数执行完毕\n')
        return wrapper


@Test.decorate
def standard_output(x, y, z):
    print(f'x={x}, y={y}, z={z}')


standard_output(3, 4, 5)

输出结果为

standard_output函数开始执行...
x=3, y=4, z=5
standard_output函数执行完毕
python内置装饰器
property和setter,deleter

先看这么一个例子

# coding=utf-8


class Student:
    
    def __init__(self, name, sex):
        self.name = name
        self.sex = sex
        self.info = f'姓名:{self.name}, 性别:{self.sex}'

    def modify_sex(self):
        self.sex = '男'


s = Student(name='刘能', sex='女')
print(s.info)
s.modify_sex()  # 此时性别变为男
print(s.info)   # 性别输出仍为女

输出结果为

姓名:刘能, 性别:女
姓名:刘能, 性别:女

虽然改变了性别,但是因为没有改变info,此时输出结果不会变

当然,可以采用下列方法,在修改sex的同时修改info

def modify_sex(self):
    self.sex = '男'
    self.info = f'姓名:{self.name}, 性别:{self.sex}'

但是程序已经成形时,在每一地方添加以上代码会耗费大量的时间,

因此我们可以把一个成员方法看作是一个变量,即使用property装饰器

# coding=utf-8


class Student:

    def __init__(self, name, sex):
        self.name = name
        self.sex = sex
        #self.info = f'姓名:{self.name}, 性别:{self.sex}'

    def modify_sex(self):
        self.sex = '男'

    @property
    def info(self):
        return f'姓名:{self.name}, 性别:{self.sex}'


s = Student(name='刘能', sex='女')
print(s.info)
s.modify_sex()
print(s.info)

输出结果为

姓名:刘能, 性别:女
姓名:刘能, 性别:男

显然,这种方法是只读的,即不能根据info函数修改对象的成员变量,所以我们可以引入setter装饰器

# coding=utf-8


class Student:

    def __init__(self, name, sex):
        self.name = name
        self.sex = sex
        self._info = f'姓名:{self.name}, 性别:{self.sex}'

    @property
    def info(self):
        return self._info

    @info.setter
    def info(self, student_info):
        if not isinstance(student_info, str):
            raise TypeError('类型错误')
        self._info = student_info


s = Student(name='刘能', sex='女')
print(s.info)
s.info = '姓名: 刘不能, 性别: 未知'
print(s.info)

输出结果为

姓名:刘能, 性别:女
姓名: 刘不能, 性别: 未知
staticmethod装饰器

staticmethod方法一般其参数与类本身、类对象无关,通过类名或者对象名调用即可

# coding=utf-8


class Dog:

    num = 0

    def __init__(self, name='lisa'):
        self.name = name
        Dog.num += 1

    @staticmethod
    def print_num():
        print(f'num={Dog.num}')

    def __del__(self):
        Dog.num -= 1


a = Dog()
b = Dog()
a.print_num()
del a
Dog.print_num()

输出结果为

num=2
num=1
classmethod装饰器

classmethod是类的方法,因为python不像c++一样可以重载,则可以用classmethod装饰器实现重载,类似于普通类方法中的self,classmethod中有关键字cls

# coding=utf-8


class Time:

    def __init__(self, second, minute, hour):
        self.second = second
        self.minute = minute
        self.hour = hour

    @classmethod
    def from_string(cls, s):
        second, minute, hour = list(map(eval, s.split(':')[:3]))
        return cls(second, minute, hour)

    @classmethod
    def from_default(cls):
        return cls(0, 0, 0)

    def __str__(self):
        return '%02d:%02d:%02d' % (self.hour, self.minute, self.second)


a = Time(11, 22, 12)
print(a)
b = Time.from_default()
print(b)
c = Time.from_string('59:59:23')
print(c)

输出结果为

12:22:11
00:00:00
23:59:59
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值