python装饰器是一个以函数作为参数并返回一个替换函数的可执行函数,在不改变函数源码的情况下为函数增添一些新功能
函数装饰器
不带参数的装饰器
python接收函数返回函数实现:
def outer(func):
def innner():
print("before func")
ret =func()
return ret+1
return innner
def func():
return 1
newfunc = outer(func)
print(newfunc())
==>
2
newfunc()就是func函数的装饰版本,注意写这种闭包函数的时候函数是否加( )(即是调用函数引用还是函数执行的问题)
利用@语法糖形式
def outer(func):
def innner():
print("before func")
ret =func()
return ret+1
return innner
@outer
def func():
return 1
func()
2
带参数的装饰器
上面的装饰器中,装饰器的唯一参数就是在执行业务的参数,装饰器的允许我们在调用时,提供其他参数,这样就为装饰器的编写和使用提供了更大的灵活性
不带参数的装饰器一般有两层,带参数的装饰器一般三层(我认为的),最内层返回原函数的调用,@得到装饰后的函数,调用的时候将返回的方法执行出来
import logging
def use_logging(level):
def decrator(func):
def wrapper():
if level=="warn":
logging.warn("this is warning")
return func()
return wrapper
return decrator
@use_logging(level="warn")
def f():
print("hello")
f()
不用语法糖的形式是:
func=use_logging(level="warn")(foo)
f()
ps:才知道竟然可以这样给嵌套函数传递参数TT
类装饰器
写一个类,里面实现init
和call
方法,call方法会别自动装饰在目标函数上,在使用@语法糖的时候,以@类名()的形式,而装饰器函数时@func的形式
class logged(object):
def __init__(self):
pass
def __call__(self, func):
def wrapped_function():
print("decorator has run")
return func()
return wrapped_function
@logged()
def f():
print("hello")
f()
==>
decorator has run
hello
装饰器的缺点
会使原函数的元信息被装饰器的信息覆盖,比如函数的_name_
def loggeg(func):
def with_logging(*args):
print(func.__name__+" is calling")
return func(*args)
return with_logging
@loggeg
def f():
print("hello")
print(f.__name__)
==>
with_logging
不加装饰器的时候输出的是f
用functools.wraps可以将原函数的元信息拷贝到装饰器函数中,这样就能让装饰器函数和原函数有一样的元信息了
from functools import wraps
def loggeg(func):
@wraps(func)#注意要传入func
def with_logging(*args):
print(func.__name__+" is calling")
return func(*args)
return with_logging
@loggeg
def f():
print("hello")
print(f.__name__)
==>
f