python有参装饰器详解_Python带参装饰器的入门路线:终于写出小白看不懂的代码了...

Python带参装饰器的入门套路

在学习带参装饰器前我们首先复习一下无参装饰器的写法:

def add(x, y):

return x + y

def logger(fn):

def wrapper(*args, **kwargs): # 这里是形参的传入,可以传入类型最终由fn|add决定

print("before the fn/add")

ret = fn(*args, **kwargs) # 这里是实参结构

print("after the fn/add")

return ret

return wrapper

add = logger(add)

add(4, 5)

# ===========output=============>

before the fn/add

after the fn/add

9

带参装饰器练习:装饰器文档字符串被改变

import time

import datetime

def logger(fn):

def wrapper(*args, **kwargs):

"""wrapper's document"""

print("before the fn")

start = datetime.datetime.now()

ret = fn(*args, **kwargs)

print("after the fn")

delta = (datetime.datetime.now() - start).total_seconds()

print("Funtion{} took {}s.".format(fn.__name__,delta))

return ret

return wrapper

@logger # equal to: add = logger(add) # add指向了wrapper

def add(x,y):

""" add's doc ~~~"""

time.sleep(1)

return x+y

print(add.__name__, add.__doc__)

# ==output不是add的document,而是wrapper的document=============>

wrapper wrapper's document

如上,使用装饰器后add的函数名和文档都被改变了。如何解决呢? 因为现在访问add函数,实际上是在执行wrapper函数,所以使用原来定义的add函数的名称和文档属性,覆盖wrapper的对应属性就可以了:

import time

import datetime

def logger(fn):

def wrapper(*args, **kwargs):

"""wrapper's document"""

print("before the fn")

start = datetime.datetime.now()

ret = fn(*args, **kwargs)

print("after the fn")

delta = (datetime.datetime.now() - start).total_seconds()

print("Funtion{} took {}s.".format(fn.__name__,delta))

return ret

def copy_properties(src, dst):

dst.__name__ = src.__name__

dst.__doc__ = src.__doc__

copy_properties(fn, wrapper)

return wrapper

@logger # equal to: add = logger(add) # add指向了wrapper

def add(x,y):

"""add's doc ~balabala~"""

time.sleep(1)

return x+y

print(add.__name__, "\n", add.__doc__)

# ==output不是add的document,而是wrapper的document=============>

add

add's doc ~balabala~

写成函数的方式

import time

import datetime

def logger(fn):

def wrapper(*args, **kwargs):

"""wrapper's document"""

print("before the fn")

start = datetime.datetime.now()

ret = fn(*args, **kwargs)

print("after the fn")

delta = (datetime.datetime.now() - start).total_seconds()

print("Funtion{} took {}s.".format(fn.__name__,delta))

return ret

wrapper.__name__ = fn.__name__

wrapper.__doc__ = fn.__doc__

return wrapper

@logger # equal to: add = logger(add) # add指向了wrapper

def add(x,y):

""" add's doc ~~~"""

time.sleep(1)

return x+y

print(add.__name__,"\n", add.__doc__)

# ==output不是add的document,而是wrapper的document=============>

add

add's doc ~~~

BTW:

类似copy_properties这种函数往往是公用的,所以定义成全局的比较合适,在调用时候,使用装饰器调用。

import time

import datetime

def copy_properties(src):

def _copy(dst):

dst.__name__ = src.__name__

dst.__doc__ = src.__doc__

return dst #这里注意return的返回值很重要,如果没有返回值,

# 如果没有返回值就是None。那么 带参装饰器里的wrapper - > copy_propertiest(fn)-> _copy -> copy(dst) - None

#这样,如果要print(add.__name__)->print(wrapper._name__)..................................print(None.__name__)

return _copy

def logger(fn):

@copy_properties(fn) #wrapper = copy_properties(fn)(wrapper)

def wrapper(*args, **kwargs):

"""wrapper's document"""

print("before the fn")

start = datetime.datetime.now()

ret = fn(*args, **kwargs)

print("after the fn")

delta = (datetime.datetime.now() - start).total_seconds()

print("Funtion{} took {}s.".format(fn.__name__,delta))

return ret

# def copy_properties(src, dst): # 这是带参装饰器的原始状态

# dst.__name__ = src.__name__

# dst.__doc__ = src.__doc__

# copy_properties(fn, wrapper)

return wrapper

@logger # equal to: add = logger(add) # add指向了wrapper

def add(x,y):

"""add's doc ~balabala~"""

time.sleep(1)

return x+y

print(add.__name__, "\n", add.__doc__)

# ==output不是add的document,而是wrapper的document=============>

add

add's doc ~balabala~

这样,一个带参装饰器就完成了。

import time

import datetime

def copy_properties(src):

def _copy(dst):

dst.__name__ = src.__name__

dst.__doc__ = src.__doc__

# return dst #这里注意return的返回值很重要,如果没有返回值,

# 如果没有返回值就是None。那么 带参装饰器里的wrapper - > copy_propertiest(fn)-> _copy -> copy(dst) - None

#这样,如果要print(add.__name__)->print(wrapper._name__)..................................print(None.__name__)

return _copy

def logger(fn):

@copy_properties(fn) #wrapper = copy_properties(fn)(wrapper)

def wrapper(*args, **kwargs):

"""wrapper's document"""

print("before the fn")

start = datetime.datetime.now()

ret = fn(*args, **kwargs)

print("after the fn")

delta = (datetime.datetime.now() - start).total_seconds()

print("Funtion{} took {}s.".format(fn.__name__,delta))

return ret

# def copy_properties(src, dst): # 这是带参装饰器的原始状态

# dst.__name__ = src.__name__

# dst.__doc__ = src.__doc__

# copy_properties(fn, wrapper)

return wrapper

@logger # equal to: add = logger(add) # add指向了wrapper

def add(x,y):

"""add's doc ~balabala~"""

time.sleep(1)

return x+y

print(add.__name__, "\n", add.__doc__)

# ===============返回值Return因一个返回值的缺失而报错=============>

---------------------------------------------------------------------------

AttributeError Traceback (most recent call last)

in

38 return x+y

39

---> 40 print(add.__name__, "\n", add.__doc__)

41 # ===============返回值Return因一个返回值的缺失而报错=============>

AttributeError: 'NoneType' object has no attribute '__name__'

带参装饰器的覆盖问题

将记录提取到控制台,或者记录到日志里面。

import time

import datetime

def copy_properties(src):

def _copy(dst):

dst.__name__ = src.__name__

dst.__doc__ = src.__doc__

return dst #这里注意return的返回值很重要,如果没有返回值,

# 如果没有返回值就是None。那么 带参装饰器里的wrapper - > copy_propertiest(fn)-> _copy -> copy(dst) - None

#这样,如果要print(add.__name__)->print(wrapper._name__)..................................print(None.__name__)

# 另外,如果return不是dst而是src,就会导致新add失效

return _copy

def logger(fn):

@copy_properties(fn) #wrapper = copy_properties(fn)(wrapper)

def wrapper(*args, **kwargs):

"""wrapper's document"""

print("before the fn")

start = datetime.datetime.now()

ret = fn(*args, **kwargs)

print("after the fn")

delta = (datetime.datetime.now() - start).total_seconds()

print("Funtion{} took {}s.".format(fn.__name__,delta))

return ret

# def copy_properties(src, dst): # 这是带参装饰器的原始状态

# dst.__name__ = src.__name__

# dst.__doc__ = src.__doc__

# copy_properties(fn, wrapper)

return wrapper

@logger # equal to: add = logger(add) # add指向了wrapper

def add(x,y):

"""add's doc ~balabala~"""

time.sleep(1)

return x+y

print(add.__name__, "\n", add.__doc__)

add(4,5)

# ==output不是add的document,而是wrapper的document=============>

add

add's doc ~balabala~

before the fn

after the fn

Funtionadd took 1.001673s.

9

Python带参装饰器的应用

检查函数执行时间。

import time

import datetime

def copy_properties(src):

def _copy(dst):

dst.__name__ = src.__name__

dst.__doc__ = src.__doc__

return dst #

return _copy

def logger(fn):

@copy_properties(fn) #wrapper = copy_properties(fn)(wrapper)

def wrapper(*args, **kwargs):

"""wrapper's document"""

print("before the fn")

start = datetime.datetime.now()

ret = fn(*args, **kwargs)

print("after the fn")

delta = (datetime.datetime.now() - start).total_seconds()

if delta > 3:

print("Function {} took {}s. It is SLOW.".format(fn.__name__, delta))

else:

print("Function {} took {}s. The speed is OK.".format(fn.__name__, delta))

print("Funtion{} took {}s.".format(fn.__name__,delta))

return ret

return wrapper

@logger # equal to: add = logger(add) # add指向了wrapper

def add(x,y):

"""add's doc ~balabala~"""

time.sleep(5)

return x+y

print(add.__name__, "\n", add.__doc__)

add(4,5)

# ==output不是add的document,而是wrapper的document=============>

add

add's doc ~balabala~

before the fn

after the fn

Function add took 5.001807s. It is SLOW.

Funtionadd took 5.001807s.

9

我们可以把delta阈值提出作为一个参数,这样就可以自定义了:

import time

import datetime

def copy_properties(src):

def _copy(dst):

dst.__name__ = src.__name__

dst.__doc__ = src.__doc__

return dst #

return _copy

def logger(duration = 3):

def _logger(fn):

@copy_properties(fn) #wrapper = copy_properties(fn)(wrapper)

def wrapper(*args, **kwargs):

"""wrapper's document"""

print("before the fn")

start = datetime.datetime.now()

ret = fn(*args, **kwargs)

print("after the fn")

delta = (datetime.datetime.now() - start).total_seconds()

if delta > duration:

print("Function {} took {}s. It is SLOW.".format(fn.__name__, delta))

else:

print("Function {} took {}s. The speed is OK.".format(fn.__name__, delta))

print("Funtion{} took {}s.".format(fn.__name__,delta))

return ret

return wrapper

return _logger

@logger(6) # equal to: add = logger(add) # add指向了wrapper

def add(x,y):

"""add's doc ~balabala~"""

time.sleep(5)

return x+y

print(add.__name__, "\n", add.__doc__)

add(4,5)

# ==output不是add的document,而是wrapper的document=============>

add

add's doc ~balabala~

before the fn

after the fn

Function add took 5.001199s. The speed is OK.

Funtionadd took 5.001199s.

9

修改为便于阅读的三元表达式:

import time

import datetime

def copy_properties(src):

def _copy(dst):

dst.__name__ = src.__name__

dst.__doc__ = src.__doc__

return dst #

return _copy

def logger(duration = 3):

def _logger(fn):

@copy_properties(fn) #wrapper = copy_properties(fn)(wrapper)

def wrapper(*args, **kwargs):

"""wrapper's document"""

print("before the fn")

start = datetime.datetime.now()

ret = fn(*args, **kwargs)

print("after the fn")

delta = (datetime.datetime.now() - start).total_seconds()

# print("Function {} took {}s. It is .".format(fn.__name__, delta)) if delta > duration else print("Function {} took {}s. The speed is OK.".format(fn.__name__, delta))

print("Function {} took {}s. It is {}.".format(fn.__name__, delta,

"slow"if delta > duration else "fast"))

return ret

return wrapper

return _logger

@logger(6) # equal to: add = logger(add) # add指向了wrapper

def add(x,y):

"""add's doc ~balabala~"""

time.sleep(5)

return x+y

print(add.__name__, "\n", add.__doc__)

add(4,5)

# ==output不是add的document,而是wrapper的document=============>

add

add's doc ~balabala~

before the fn

after the fn

Function add took 5.001629s. It is fast.

9

为了灵活,我们对超出阈值的信息使用一个函数记录:

import time

import datetime

def copy_properties(src):

def _copy(dst):

dst.__name__ = src.__name__

dst.__doc__ = src.__doc__

return dst #

return _copy

def logger(duration = 3, output = lambda name, delta: print("slow.{} took {}s )".format(name, delta))):

def _logger(fn):

@copy_properties(fn) #wrapper = copy_properties(fn)(wrapper)

def wrapper(*args, **kwargs):

"""wrapper's document"""

print("before the fn")

start = datetime.datetime.now()

ret = fn(*args, **kwargs)

print("after the fn")

delta = (datetime.datetime.now() - start).total_seconds()

if delta > duration:

output(fn.__name__, delta) #这里的output指代的是函数一个函数,

return ret

return wrapper

return _logger

@logger(2) # equal to: add = logger(add) # add指向了wrapper

def add(x,y):

"""add's doc ~balabala~"""

time.sleep(3)

return x+y

print(add.__name__, "\n", add.__doc__)

add(4,5)

# ==output不是add的document,而是wrapper的document=============>

add

add's doc ~balabala~

before the fn

after the fn

slow.add took 3.000753s )

9

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值