python装饰器学习

装饰器是Python的一个重要的组成部分,是修改的其他函数的功能函数的功能函数,有助于缩短代码。xi下面介绍如何使用装饰器类.

1,函数装饰器

如果我们想给函数曾江额外的操作,但是不更改函数的内部结构,可以通过给函数添加装饰器来实现。

1.1函数添加装饰器

def time_use(func):
    # Decorator that reports the execution time
    # parame func:
    # return :
    @wraps(func)
    def wrapper(*args, **kwargs):
        start  = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f'func name:{func.__name__},time used:{end-start}')
        return result
    return wrapper
@time_use
def count_down(n):
    # Counts down
    # :param n:
    # :return:
    while n > 0:
        n-=1
count_down(100000)
count_down(1000000)
        

输出为:

func name:count_down,time used:0.02700519561767578
func name:count_down,time used:0.26958799362182617

观察上述例子发现,time_use(func)表示对应的修饰器func表示被修饰的函数。

装饰器使用了*args, **kwargs来接收任意参数的函数

1.1装饰器中保留的函数元信息

在实际的应用中会发现,我们把装饰器作用在某个函数后发现该函数逇重要的元信息的比如,名字,文档字符串,注解和参数签名都丢失了但是我们希望保留的这些信息。

故,在定义装饰器的时候,我们应该使用functool库中的@wraps装饰器来注解底层包装函数

from functools import wraps
import time
def time_use(func):
    # Decorator that reports the execution time
    # parame func:
    # return :
    # 保留原函数的元信息
    @wraps(func)
    def wrapper(*args, **kwargs):
        start  = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f'func name:{func.__name__},time used:{end-start}')
        return result
    return wrapper
#  使用被包装后的函数,检测对应的元信息
@time_use
def count_down(n):
    # Counts down
    # :param n:
    # :return:
    while n > 0:
        n-=1
count_down(100000)
print(f'func name:{count_down.__name__}')
print(f'func name:{count_down.__doc__}')

输出为:

func name:count_down,time used:0.02752208709716797
func name:count_down
func name:None

1.3 解除装饰器

对于已经使用了装饰器的函数,我们有时又会期望回到原始的,没有被装饰的状态。

from functools import wraps
import time
def time_use(func):
    # Decorator that reports the execution time
    # parame func:
    # return :
    # 保留原函数的元信息
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f'func name:{func.__name__},time use:{end-start}')
        return result
    return wrapper
    
@time_use
def add(x,y):
    # Counts down
    # :param n:
    # :return:
    return x+y

print(add(1,2))

add1 = add.__wrapped__
print(add1(1,2))

输出结果为:

func name:add,time use:9.059906005859375e-06
3

@wraps一个重要的特征是,他能通过属性的__wrapped__直接访问被包装的函数。

1.4 带参数的装饰器

在实际应用中,我们有时候希望装饰器可以带参数,或者说定义一个可以带参数的装饰器

from functools import wraps
import time
import logging

def logged(level,name=None,message=None):
    def decorate(func):
        logname = name if name else func.__module__
        log = logging.getLogger(logname)
        logmsg = message if message else func.__name__
        @wraps(func)
        def wrapper(*args, **kwargs):
            log.log(level,logmsg)
            return func(*args, **kwargs)
        return wrapper
    return decorate
@logged(logging.DEBUG)
def add(x,y):
    return x + y

@logged(logging.CRITICAL,"examples")
def spam():
    print("spam")
    
print(f"func name:{add(2,3)}")
print(f"func name:{spam()}")

输出的结果为:

func name:5
spam
spam
func name:None

2,类中定义装饰器

类中定义装饰器很简单,首先要确认它的使用方式。到底是作为一个实例方法还是类方法

from functools import wraps
class A:
    #Decorators  as a instance method
    def decorator_1(self,func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            print(f"Decorator - 1 ")
            return func(*args, **kwargs)
        return wrapper
    def decorator_2(self,func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            print(f"Decorator - 2 ")
            return func(*args, **kwargs)
        return wrapper
    
a = A()

# 实例调用
@a.decorator_1
def spam():
    print(f"Spam=1")

# 类调用
@A.decorator_1
def spam1():
    print(f"Spam=2")

通过观察可以发现,装饰器的调用,一个是实例调用,一个是类调用。

2.1 装饰器定义为类

在实际的应用中,我们需要使用一个装饰器取包装函数,但是希望返回的一个可以调用的实例,并且的需要装饰器的可以同时工作在的类定义的内部和外部

为了将装饰器定义为一个实例,我们需要的确保的它实现了__call__()方法和__get__()方法。

from functools import wraps
import types

class Profile:
    def __init__(self,func):
        wraps(func)(self)
        self.ncalls = 0;
    def __call__(self,*args,**kwargs):
        self.ncalls += 1
        print(f"555")
        return self.__wrapped__(*args,**kwargs)
    def __get__(self,instance,cls):
        if instance is None:
            return self
        else :
            return types.MethodType(self, instance)
        
@Profile
def add(x,y):
    return x+y

class Spam:
    @Profile
    def bar(self,x):
        print(f"object:{self},param is {x}")
    
print(f"number add result:{add(5,2)}")
print(f"number add result:{add(5,8)}")

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值