装饰器functools wraps, update_wrapper, partial 以及 装饰器传参

发布时间 2023-04-20 10:29:29作者: 记不起的回忆

partial、update_wrapper、wraps的使用

引用

from functools import wraps, update_wrapper, partial

1. partial

partial又叫偏函数。函数在执行的时候需要带上必要的参数,有些参数是执行之前就是可知的,这种情况下,一个函数有一个或者多个函数预先就能用上,以便函数能够更少的参数进行调用。

# 定义一个函数
def add(x, y): 
    return x + y

add1 = partial(add, y=3) # 这里创建了一个新的函数

print add1(4) # 7
print add(x=4, y=9) # 13

2. update_wrapper

update_wrapper这个函数的主要功能是负责copy原函数的一些属性,如moudle、name、doc、等,如果不加update_wrapper,那么被装饰器修饰的函数就会丢失其上面的一些属性信息

# 定义装饰器
def wrapper(f):
    def wrapper_function(*args, **kwargs):
        return f(*args, **kwargs)
    update_wrapper(wrapper_function, f)
    return wrapper_function

@wrapper
def wrapped():
    pass

print(wrapped.__doc__) # 输出`这个是被修饰的函数`
print(wrapped.__name__) # 输出`wrapped`
# __doc__和__name__属性已经是wrapped函数中的,当然,update_wrapper函数也对__module__和__dict__等属性进行了更改和更新

3. wraps

被装饰器修饰后的函数会编程另外一个函数,为了不受影响,利用wraps来消除这样的副作用,使它能够保持原函数的属性。

# 定义装饰器
def wrapper(f):
    @wraps(f)
    def wrapper_function(*args, **kwargs):
        return f(*args, **kwargs)
    return wrapper_function

@wrapper 
def wrapped(): 
    pass

带参数的装饰器

来想想这个问题,难道@wraps不也是个装饰器吗?但是,它接收一个参数,就像任何普通的函数能做的那样。
那么,为什么我们不也那样做呢? 这是因为,当你使用@my_decorator语法时,你是在应用一个以单个函数作为参数的一个包裹函数。
记住,Python里每个东西都是一个对象,而且这包括函数!记住了这些,我们可以编写一下能返回一个包裹函数的函数。

在函数中嵌入装饰器
创建一个包裹函数,能让我们指定一个用于输出的日志文件。

from functools import wraps 


def logit(logfile='out.log'): 
    def logging_decorator(func): 
        @wraps(func) 
        def wrapped_function(*args, **kwargs): 
            log_string = func.__name__ + " was called" 
            print(log_string) 
            # 打开logfile,并写入内容 
            with open(logfile, 'a') as opened_file: 
                # 现在将日志打到指定的logfile 
                opened_file.write(log_string + '\n') 
            return func(*args, **kwargs) 
        return wrapped_function 
    return logging_decorator 

@logit() 
def myfunc1(): 
    pass 

myfunc1() 
# Output: myfunc1 was called 
# 现在一个叫做 out.log 的文件出现了,里面的内容就是上面的字符串 

@logit(logfile='func2.log') 
def myfunc2(): 
    pass 

myfunc2() 
# Output: myfunc2 was called 
# 现在一个叫做 func2.log 的文件出现了,里面的内容就是上面的字符串