请问廖老师,像这样wrapper函数没有return的情况下,是否也算是装饰器呢?
Topic source@VV谢小鑫 那函数装饰任何有返回值的函数结果都会变得None,改变原函数行为的都不能算是装饰器。
def callbe(func):
def wrapper(*args,**kw):
print('begin call: %s' % func.__name__)
func(*args,**kw)
print ('end call: %s' % func.__name__)
return wrapper
@callbe
def add_one(num):
retrun num + 1
print(add_one(2))
# begin call: add_one
# None
# end call: add_one
@灰手 的解释是对的,但是不太容易懂,我来解释一下。 首先@灰手 的输出是错的,不知道是不是有意的。我用的是pycharm 2016.1.4,JRE1.8.0,Python3.5.2,输出是:
begin call: add_one
end call: add_one
None
假定你已经深刻理解了廖老师说的: “decorator就是一个返回函数的高阶函数” 所以@灰_手 的程序等价于:
...
def add_one(num): ①
retrun num + 1 ②
add_one = callbe(add_one) ③
...
而③又等价于add_one = wrapper。那么接下来就明显了: print(add_one(2)) 先调用了add_one即wrapper,而wrapper里现在是什么呢
print('begin call: %s' % func.__name__)
func(*args, **kw) # 以传入的参数调用func函数,所以这句等价于3
print('end call: %s' % func.__name__)
即wrapper里等价于
print('begin call: %s' % func.__name__)
3
print('end call: %s' % func.__name__)
这个‘3’没有对象接收!!! 即@灰_手 说的:“值没有被正确返回”,所以不会被打印!!!所以那个return是必要的!!! 至于第三行的输出为什么是None。因为现实调用add_one即调用wrapper会输出前两行,然后print(add_one(2))会输出add_one这个变量本身!(因为上面所说的那个‘3’没有被add_one接收!!)而add_one现在指向wrapper,但是wrapper函数不在这句print的作用域之内!!所以最后一行输出为None。 啊好绕啊。
LS基本正解。我懒得运行,导致输出顺序有误。但有一个地方需要更正的是:任何函数都有返回值,如果没有显式return
的话,在函数最后会自动加一句return None
的。wrapper
函数就是因为没有显式返回,所以它的返回值是None
,于是任何一个被包装的函数最终返回值都是None
明白了。
原代码:
def callbe(func):
def wrapper(*args,**kw):
print('begin call: %s' % func.__name__)
func(*args,**kw)
print ('end call: %s' % func.__name__)
return wrapper
@callbe
def log():
print('Hello,world!')
下面是我的分析,供大家参考:
log在运行时实际上是这样的:
log = callbe(log)
因为callbe的返回值是wrapper,所以:
log = wrapper
当调用log时,实际上调用的是wapper:
log() == wrapper()
wapper函数体如下:
print('begin call: %s' % func.__name__)
func(*args,**kw)
print ('end call: %s' % func.__name__)
基于闭包机制,wrapper会自动记住上层函数赋值给func的log函数对象:
callbe(log) # func = log
func函数体如下:
print('Hello,world!')
可以看到func的函数体没有return,所以默认返回None,可以手动测试:
>>> def test():
... print('Hello,world!')
...
>>> x = test()
Hello,world!
>>> print(x)
None
再来看wrapper,wrapper函数体也没有return:
def callbe(func):
def wrapper(*args,**kw):
print('begin call: %s' % func.__name__)
func(*args,**kw)
print ('end call: %s' % func.__name__)
return wrapper
所以wrapper也返回了None:
>>> print(log())
begin call: log
Hello,world!
end call: log
None
装饰器的定义是:“为函数动态添加一些功能,并不能改变原函数的行为”。将这个定义应用到本例中可以发行:wrapper返回了自己的None,而非func的None。也就是说wrapper改变了func的返回值...
为了更能说明问题,增加一个返回值为2的装饰函数:
@callbe
def test():
return 2
由装饰器的定义可以知道,wrapper应该返回函数的值,也就是2。
现在打印该装饰函数的调用结果:
>>> print(test())
begin call: test
end call: test
None
wrapper返回了None却不是2。
正确的写法如下:
def callbe(func):
def wrapper(*args,**kw):
print('begin call: %s' % func.__name__)
result = func(*args,**kw)
print ('end call: %s' % func.__name__)
return result
return wrapper
@callbe
def test():
return 2
调用后,可以看到如下结果:
>>> print(test())
begin call: test
end call: test
2
wrapper返回了test的返回值2。
- 1
- 2
萌13131313
请问廖老师,像这样wrapper函数没有return的情况下,是否也算是装饰器呢?