decorator
Topic sourcereturn decorator(x) # 此时返回的是wrapper
请问此处在log无参的情况下为什么会返回wrapper? decorator接受一个func参数,若不是函数参数则wrapper中的func.name 无法打印,那log无参的情况传入decorator的参数是什么? 此时定义一个b() @log
def b(): print('123')
则b是如何由log演化而来?,即b = ?
谢谢大神了!
举个简单的例子:
借用大佬代码
def log(x):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('%s%s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
if isinstance(x, str):
text = x + ' '
return decorator
else:
text = ''
return decorator(x) # 此时返回的是wrapper
需求:公司的人事部(str)和技术部(func)分别需要一个员工;
1.正常情况下,招聘两个人分别去各自的部门,互不干扰(也就是log
携带的参数(员工)去人事部;调用函数时传递的func
参数(员工)去技术部;);
2.然鹅,入职时,来人事部报道的只有一位员工,该怎么分配呢?
3.问询之后,发现他是(str),那他就是人事部的员工,后来的那个肯定是技术部的;
4.问询之后,发现他是技术部的,那么就让人事部先空缺text=''
,让他去技术部return decorator(x)
;
感谢回复,我理解的您的意思是: @log
def b(): print('123') 这段代码看似是log没传入任何参数,实际上是把b作为一个函数对象传入了log中,也就是说是return decorator(b)
不知对否?
可以这么理解,但有点牵强。
调用这段代码的流程一般是这样的:
1.log
带参数
@log('call')
def b():
print('123')
在log
带参数的时候好理解,因为有两个参数,所以参数会依次传递,所以call
传给了log()
,text
接收了call
, b()
传给了decorator()
,func
接收的就是b()
;
2.log
不带参数
@log
def b():
print('123')
在log
不带参数的时候,也就是只传入了b()
,但不知道是传给谁的参数(其实默认是传给log()
的,参数会依次传嘛,也就是位置参数),
def sum(x, y):
return x + y
sum(3, 5)
sum(5, 3)
# 虽然结果相同,但 x 和 y 传递的顺序不同,两次的 x 和 y 就不同
# 带参数和不带参数其实就像这样
sum(3, 5)
sum( , 5)
然鹅,log()
接收了这个参数,decorator()
却没有收到自己需要的参数,这时就会报错:‘都是必传参数,为什么给它不给我?’,怎么办?那就给text
默认一个参数:text = ''
,然后必须把x
显示
的传递(不显示传递,还是会默认为是 log 的参数)给decroator()
:return decroator(x)
,这里可以抽象的理解为:
@log('')
def b():
print('123')
这样,它们都有了自己需要的参数,然后就愉快的执行了。
其实这里只是简单的判断了,x
不是 str
,那它就是function
,所以当x
不是str
时,就认为它是 func
,而func
是decroator
的参数而不是log
所需要的str
,所以必须显示的把func
给decroator
,但因为log
也需要一个必传参数,所以要给它指定一个算是默认参数的值text = ''
;
为什么 text='' 叫默认参数的值?这只是一个格式吧。不是说 log 需要一个必传参数,而是参数类型改变了。。就像函数的复合,现在要对一次和两次复合都成立。所以不嫌麻烦的话完全可以把情况分清楚:
def log(x):
if isinstance(x, str):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('%s %s():' % (x, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
else:
@functools.wraps(x)
def wrapper(*args, **kw):
print('%s():' % x.__name__)
return x(*args, **kw)
return wrapper
回复楼上的@fomiuna 同学:
当log
不带参数时,需要一句text = ''
是因为函数wrapper()
里引用到了text
这个变量,如果不事先定义就会报错。
另外,既然您都觉得您写的这段代码比较麻烦,那么为什么不参考一下楼里的另一种写法呢?实现效果是一样的:)
- 1
- 2
KonoNA7
练习题:
在函数调用的前后打印出
'begin call'
和'end call'
的日志:既支持
@log
又支持@log('execute')
: