在网上看了几篇文章,要么解释不清,要么代码运行不了。综合几篇文章,排完代码的坑,分享一下。
不带参数的单一使用
先声明这段代码我没运行,因为比较简单,看看就行了。
def spamrun(fn):
def sayspam(*args):
print("spam,spam,spam")
fn(*args)
return sayspam
@spamrun
def useful(a,b):
print(a*b)
if __name__ == "__main__"
useful(2,5)
作者:陆_离
链接:https://www.jianshu.com/p/7a644520418b
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
我们可以简单的把这个代码理解为:
if __name__ == "__main__"
useful = spamrun(useful)
useful(a,b)
不带参数的多次使用
def spamrun(fn):
print("run:"+fn.__name__)
def sayspam(*args):
print("spam,spam,spam")
fn(*args)
return sayspam
def spamrun1(fn):
print("run1:"+fn.__name__)
def sayspam1(*args):
print("spam1,spam1,spam1")
fn(*args)
return sayspam1
@spamrun
@spamrun1
def useful(a,b):
print(a*b)
if __name__ == "__main__":
useful(2,5)
运行结果为:
run1:useful
run:sayspam1
spam,spam,spam
spam1,spam1,spam1
10
运行过程是这样的:
useful(2,5) 变为 spamrun(spanmrun1(useful)(2,5))
首先解析 spamrun ,发现里边的参数无法给参数 fn 赋值,只能先把里边的 spanmrun1(useful) 先解析出来,看是什么东西。
于是解析 spanmrun1(useful) ,输出了 run1:useful .整个式子变成 spamrun(sayspam1(2,5)) 。这时回到外层继续运行spamrun。输出 run:sayspam1 。并且返回 syspam() 。整个式子变成 sayspam(2,5) 。
这时候,运行,打印 spam,spam,spam 。注意这时的 fn=sayspam1 ,所以继续运行 sayspam1(2,5) .
最后是运行 print(a*b) 语句。
带参数的多次使用
检查函数的输入输出是否符合标准,比如我们希望的输入是(int,(int,float))输出是(int,float),这个例子在官网里有,但是在3.6版本中使用有些问题,这里进行了一些改动,如果要进一步了解可以看下functionTool。
import functools
def accepts(*types):
def check_accepts(f):
def new_f(*args, **kwds):
assert len(types) == (len(args) + len(kwds)), \
"args cnt %d does not match %d" % (len(args) + len(kwds), len(types))
for (a, t) in zip(args, types):
assert isinstance(a, t), \
"arg %r does not match %s" % (a, t)
return f(*args, **kwds)
functools.update_wrapper(new_f, f)
return new_f
return check_accepts
def returns(rtype):
def check_returns(f):
def new_f(*args, **kwds):
result = f(*args, **kwds)
assert isinstance(result, rtype), \
"return value %r does not match %s" % (result, rtype)
return result
functools.update_wrapper(new_f, f)
return new_f
return check_returns
@accepts(int, (int, float))
@returns((int, float))
def func(arg1, arg2):
return arg1 * arg2
if __name__ == "__main__":
a = func(1, 'b')
print(a)
运行结果:
Traceback (most recent call last):
File "test111.py", line 39, in <module>
a = func(1, 'b')
File "test111.py", line 10, in new_f
"arg %r does not match %s" % (a, t)
AssertionError: arg 'b' does not match (<class 'int'>, <class 'float'>)
还是和上面一样的一步步分析。
之前看到有的代码直接用 new_f.__name__=f.__name__ 是不行的,这里用的 update_wrapper() 。我没有深究,大概的意思就是这样能把整个函数的运行上下文都给传过去。