Python 装饰器

装饰器概念

装饰器(decorators)是 Python 中的一种高级功能,它允许你动态地修改函数或类的行为。

装饰器是一种函数,它接受一个函数作为参数,并返回一个新的函数或修改原来的函数。

说白了装饰去本质上是一个 Python 函数(其实就是闭包),它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。

装饰器的语法使用 @decorator_name 来应用在函数或方法上。

Python 还提供了一些内置的装饰器,比如 @staticmethod 和 @classmethod,用于定义静态方法和类方法。

def print_function_name(func):
    print(func.__name__)
    return func

@print_function_name
def func1():
    print("函数1运行")


# 函数在声明时,如果我们添加了装饰器,那么装饰器在声明时就被调用了
func1()

# 结果是 func1 函数1运行

装饰器的应用场景

  • 日志记录: 装饰器可用于记录函数的调用信息、参数和返回值。
  • 性能分析: 可以使用装饰器来测量函数的执行时间。
  • 权限控制: 装饰器可用于限制对某些函数的访问权限。
  • 缓存: 装饰器可用于实现函数结果的缓存,以提高性能。

装饰器函数中的参数传递

我们使用一个日志的打印的案例来说明

def print_log(func):
    print(func)
    return func

@print_log
def func1(a,b):
    print("函数1被运行",a,b)
    
func1(1,2)

函数参数传递演变1,func1 如果不调用,inner 不会被执行

def print_log(func):
    print(func)
    def inner(x,y):
        x += 1
        y += 1
        print("参数列表是:",x,y) 
    return inner

@print_log
def func1(a,b):
    print("函数1被运行",a,b)
    
func1(1,2)  # 结果: 
                # 参数列表是: 2 3
                # <function func1 at 0x1044f68e0>

函数参数传递演变2

def print_log(func):
    print(func)
    def inner(x,y):
        print("参数列表是:",x,y)
        return func(x,y)
    return inner

@print_log               
def func1(a,b):
    print("函数1被运行",a,b)
    return a + b
    
r = func1(10,20)
print(r) 

# 执行结果是:首先装饰器一声明,就会执行:<function func1 at 0x1046228e0>
#           func1 方法调用,就会执行 inner 参数列表是: 10 20,接着执行 函数1被运行 10 20 , 接着是 None

调用 func1 ,需要在 inner 将结果返回给 r

def print_log(func):
    print(func)
    def inner(x,y):
        print("参数列表是:",x,y)
        return func(x,y)
    return inner

@print_log               
def func1(a,b):
    print("函数1被运行",a,b)
    return a + b
    
r = func1(10,20)
print(r) 

# 执行结果是:首先装饰器一声明,就会执行:<function func1 at 0x1046228e0>
#           func1 方法调用,就会执行 inner 参数列表是: 10 20,接着执行 函数1被运行 10 20 , 接着是 30

函数参数传递演变3—动态参数

def print_log(func):
    print(func)
    def inner(*args,**kwargs):
        print("参数列表是:",args,kwargs)
        return func(*args,**kwargs)
    return inner

@print_log
def func1(a,b,c,d,e=1,f=2):
    print("函数1被运行",a,b,c,d)
    return a + b+c+d
    
r = func1(10,20,30,40,e=1,f=2)
print(r) 

演变 4

def print_log(type):
    print(type)
    def warpper(func):
        print(func)
        def inner(*args,**kwargs):
            if type=="控制台":
                print("参数列表是:",args,kwargs)
            elif type == "文件":
                print("我已经把日志输出到文件中了")
            return func(*args,**kwargs)
        return inner 
    return warpper


@print_log("控制台")
def func1(a,b,c,d,e=1,f=2):
    print("函数1被运行",a,b,c,d)
    return a + b+c+d
    
r = func1(10,20,30,40,e=1,f=2)
print(r)


@print_log("文件")
def func2(a,b):
    print("函数1被运行",a,b)
    return a + b
    
r = func2(100,200)
print(r)

理解 yield 关键字与生成器对象

在 Python 中,使用了 yield 的函数被称为生成器(generator)。

yield 是一个关键字,用于定义生成器函数,生成器函数是一种特殊的函数,可以在迭代过程中逐步产生值,而不是一次性返回所有结果。

跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。

当在生成器函数中使用 yield 语句时,函数的执行将会暂停,并将 yield 后面的表达式作为当前迭代的值返回。

调用一个生成器函数,返回的是一个迭代器对象。

def countdown():
    print("函数func2被调用1")
    yield 2
    print("函数func2被调用2")
    yield 3
    print("函数func2被调用3")
    yield 4

# 创建生成器对象
f2 = countdown()
print(f2)
# 启动生成器对象
r2 = f2.__next__()  // 执行 f2.__next__() 会打印:函数func2被调用1,并且将 2 返回
print(r2)
r3 = f2.__next__()
print(r3)
r4 = f2.__next__()
print(r4)

然后,每次调用生成器的 next() 方法或使用 for 循环进行迭代时,函数会从上次暂停的地方继续执行,直到再次遇到 yield 语句。这样,生成器函数可以逐步产生值,而不需要一次性计算并返回所有结果。

def countdown():
    print("函数func2被调用1")
    yield 2
    print("函数func2被调用2")
    yield 3
    print("函数func2被调用3")
    yield 4

# 创建生成器对象
f2 = countdown()

for i in range(5):
    print(i)

for f in f2:
    print(f)

生成器函数的优势是它们可以按需生成值,避免一次性生成大量数据并占用大量内存。此外,生成器还可以与其他迭代工具(如for循环)无缝配合使用,提供简洁和高效的迭代方式。

def func3():
    num = yield 1
    print(num)
    num1 = yield num + 10
    print(num1)
    yield  num1 + 10

f3 = func3()
print(f3)
r1 = f3.send(None) // send是生成器的方法,第一次 send 必须是 None
print("r1的值",r1)
r2 = f3.send(2) // 这里传入的值:2 ,就是传给了
print("r2的值",r2)
r3 = f3.send(3)
print("r3的值",r3)

第一次 send(None), fun3中的 num 的值是 1,所以r1的值就是 1

第二次 send(2),2给了fun3中的 num ,生成器返回的值就是 12

第三次 send(3), 3给了fun3中的 num1 ,生成器返回的值就是 13

生产者与消费者的案例

def customer():
    while True:
        n = yield
        if not n:
            return
        print("消费者消费了{}号包子".format(n))

# 生产者代码
def product(c):
    # 消费者的生成器启动
    c.send(None)
    for i in range(5):
        print("生产者生产了{}号包子".format(i))
        # 我们需要告诉消费者可以消费了
        c.send(str(i))

c = customer()
product(c)

基于装饰器实现龟兔赛跑案例

使用装饰器统计兔子函数和乌龟函数的运行时间

兔子每跑5米则随机休息1到10秒

乌龟每跑1米则固定休息1秒

最后统计兔子函数和乌龟函数的运行时间

# 导入一个随机的工具, 这里是导入随机模块
import random
# 导入时间工具
import time

# 定义一个跑道的长度
track_length = 10


# 定义装饰器
def runtime_log(type):
    def runtime(func):
        def inner():
            print("{}开始奔跑了".format(type))
            start_time = time.time()
            func()
            end_time = time.time()
            print("<{}>的运行时间是:{:.2f}".format(type,end_time-start_time))
        return inner
    return runtime


@runtime_log("乌龟")
def wugui():
    for i in range(1,track_length+1):
        print("乌龟跑了{}米".format(i))
        time.sleep(1)

@runtime_log("兔子")
def tuzi():
    for i in range(1,track_length+1):
        if i % 5 == 0:
            time.sleep(random.randint(1,15))
        print("兔子跑了{}米".format(i))

wugui()
tuzi()

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值