【python】python装饰器|python装饰器用法|为什么要用python装饰器

写Python不用装饰器的话怎么装逼呢??

 

一、为什么要用装饰器(decorator)

以一个需求来说明:比如要判断一个数字是否是质数,可以给出如下方法:

def is_prime(num):
    if num<2:
        return False
    elif num==2:
        return True
    else:
        for i in range(2,num):
            if num%i==0:
                return False
        return True

追加需求:如果是质数的话,请将质数打印,范围是1-10000,可以追加代码如下:

def is_prime(num):
    if num<2:
        return False
    elif num==2:
        return True
    else:
        for i in range(2,num):
            if num%i==0:
                return False
        return True

def prime_nums():
    for i in range(2,10001):
        if is_prime(i)
            print(i)

追加需求:要求打印程序运行时间,修改代码如下:

# -*- coding:utf-8 -*-
import time

def is_prime(num):
    if num<2:
        return False
    elif num==2:
        return True
    else:
        for i in range(2,num):
            if num%i==0:
                return False
        return True

def prime_nums():
    time1 = time.time()
    for i in range(2,10001):
        if is_prime(i):
            print(i)
    print(time.time()-time1)

prime_nums()

其实仔细思考一下程序的写法,类似计时这样的需求可能会被重复用到,其代码在整个文件中会被多处用到,而且其代码会与其他的逻辑代码在书写布局上产生交叉,并且像质数判断的函数在其他地方可能变成了别的函数,将其单独分离成一个个方法进行调用也可以,但未免麻烦,这种情况下使用装饰器是一个更加优秀的解决方案。

 

二、如何使用呢

继续使用上面的例子,先给装饰器如下。装饰器说白了也是一个函数,其参数是另外一个将会调用的函数名。下面这段代码的含义就是将计算运行时间的功能运用到 func这个函数上面。

def display_time(func):
    def wrapper(): # wrapper函数表示函数的功能
        time1 = time.time()
        func()   # 被调用的函数,比如可以换成prime_nums
        print(time.time()-time1)
    return wrapper

那么如果 prime_time() 函数要用到这个装饰器来获取运行时间的话,只要在 prime_time() 函数上方书写“@dispaly_time”即可。装饰器也改变了函数的执行流程,当调用了装饰器的函数开始运行时,并不会直接运行此函数,而是跳转到装饰器运行wrapper()中的内容。修改代码如下:

# -*- coding:utf-8 -*-
import time

def display_time(func):
    def wrapper(): # wrapper函数表示函数的功能
        time1 = time.time()
        func()   # 被调用的函数,比如可以换成prime_nums
        print(time.time()-time1)
    return wrapper
    
def is_prime(num):
    if num<2:
        return False
    elif num==2:
        return True
    else:
        for i in range(2,num):
            if num%i==0:
                return False
        return True

@display_time
def prime_nums():
    for i in range(2,10001):
        if is_prime(i):
            print(i)

prime_nums()

需求又追加:打印质数的个数。这就需要在 prime_nums() 中返回一个 count。注意为什么不直接打印呢,这是一个编程习惯,一般一个函数实现了某个功能后会将实现结果返回。代码修改如下:

@display_time
def count_prime_nums():
    count = 0
    for i in range(2,10001):
        if is_prime(i):
            count = count + 1
    return count

count = count_prime_nums()
print(count)

可以看到运行时间打印了,可质数的个数并没有打印,很简单,因为 count_prime_nums() 返回的 count 并没有传到装饰器中,因此可以在装饰器中加一个接收 count_prime_nums() 执行结果的变量,然后 return 该变量即可,注意是return而不是print,这点很重要。代码修改如下,改了下时间输出格式。

# -*- coding:utf-8 -*-
import time

def display_time(func):
    def wrapper(): # wrapper函数表示函数的功能
        time1 = time.time()
        result = func()   # 被调用的函数,比如可以换成prime_nums
        print("Total time:{:.4} s".format(time.time()-time1)) # 4位小数输出时间
        return result
    return wrapper
    
def is_prime(num):
    if num<2:
        return False
    elif num==2:
        return True
    else:
        for i in range(2,num):
            if num%i==0:
                return False
        return True

@display_time
def count_prime_nums():
    count = 0
    for i in range(2,10001):
        if is_prime(i):
            count = count + 1
    return count

count = count_prime_nums()
print(count)

再次追加需求:计算从 1到 maxnum 的质数个数,而不是简单的10000。其实只要给 count_prime_nums() 加一个参数即可,比如这样:

@display_time
def count_prime_nums(maxnum):
    count = 0
    for i in range(2,maxnum+1):
        if is_prime(i):
            count = count + 1
    return count

count = count_prime_nums(10000)
print(count)

但如何修改装饰器呢,不修改装饰器程序会报错,因此需要在装饰器的 wrapper() 中追加参数,然后在 func() 中也写上即可。但是但是,这里 count_prime_nums() 只用了一个参数,你可以在 wrapper 中指定,那换了一个别的函数可能会用到不同数量的参数,总不能一个一个地修改吧,这时就体现出了装饰器的另外一个强大之处,可以把 wrapper() 的参数写成 wrapper(*args),表示n个参数,然后 func(*args) 即可。最终代码如下:

# -*- coding:utf-8 -*-
import time

def display_time(func):
    def wrapper(*args): # wrapper函数表示函数的功能
        time1 = time.time()
        result = func(*args)   # 被调用的函数,比如可以换成prime_nums
        print("Total time:{:.4} s".format(time.time()-time1)) # 4位小数输出时间
        return result
    return wrapper
    
def is_prime(num):
    if num<2:
        return False
    elif num==2:
        return True
    else:
        for i in range(2,num):
            if num%i==0:
                return False
        return True

@display_time
def count_prime_nums(maxnum):
    count = 0
    for i in range(2,maxnum+1):
        if is_prime(i):
            count = count + 1
    return count

count = count_prime_nums(10000)
print(count)

 

 

总结:

python 装饰器很强大,可以用来解决实际问题,要经常用。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值