我正在尝试测试对包装函数的理解,因此构建了这段代码
def wrapper():
print ("Wrapper")
def wrapped():
print ("Wrapped")
return wrapped
if int (wrapper()):
print ("Returned integer")
我尝试了if str(wrapper())
和if callable (wrapper())
,没关系
我不明白为什么if int (wrapper())
会产生错误:
Exception has occurred: TypeError
int() argument must be a string, a bytes-like object or a number, not 'function'
当然应该只说False,根本没有错误吗?
答案 0 :(得分:2)
我不知道您正在测试什么,但是我可以尝试解释您的代码做什么。
案例1:if str(wrapper())
调用wrapper()
时,它会打印“包装器”,然后返回一个名为wrapped
的函数。
因此,调用str(wrapper())
等效于str(wrapped)
。请注意,wrapped
之后没有括号。这意味着str
函数的参数是函数对象。
在功能对象上调用str
时,它将返回带有函数名称和位置的字符串。检查以下示例:
>>> def test():
... pass
...
>>> str(test)
'<function test at 0x7fa95c504668>'
>>> type(str(test))
<type 'str'>
if str(wrapper())
的评估结果为if '<function wrapped at 0x7fa95c504668>'
。>>> if "string":
... print("Non empty string")
...
Non empty string
>>> if "":
... print("This line will not be printed")
...
>>>
案例2:if callable(wrapper())
与以前相同
callable
检查对象是否具有__call__
属性
调用callable(wrapper())
等效于callable(wrapped)
。由于wrapped
是一个函数,因此它具有__call__
属性,并且表达式的计算结果为True
。
因此if callable(wrapper())
的计算结果为if True
,如果执行if语句!
案例3:if int(wrapper())
与以前相同
int
只能 将数字和字符串转换为整数。
int(wrapper())
等效于int(wrapped)
。因此,您尝试使用函数对象!
int
int
无法将功能对象转换为整数并给出箭头消息:
Exception has occurred: TypeError
int() argument must be a string, a bytes-like object or a number, not 'function'
答案 1 :(得分:1)
Decorator只是一个函数的奇特名称,该函数将一个函数作为参数并返回一个函数。因此,装饰器的一个示例是:
def wrapper(func):
print ("Wrapper")
def wrapped(*args, **kwargs):
print ("Wrapped")
func(*args, **kwargs)
return wrapped
@wrapper
def to_wrap():
print("decorated function")
如果您运行to_wrap()
,则实际上您正在运行wrapped()
等于func
的{{1}}。
因此,请记住这个想法,让我们来看一下您的代码:
to_wrap
if int (wrapper()):
print ("Returned integer")
返回的是一个函数(在您的代码或上面的修改中),然后您尝试将其转换为wrapper()
并检查其布尔值。此转换未实现,因此Python引发TypeError,因为函数类型的对象无法转换为整数类型。
答案 2 :(得分:1)
仍然需要调用装饰器。您现在拥有的是 closure ,它返回一个函数:
def f():
def wrapped():
return 10
return wrapped
x = f()
# x is the function 'wrapped'
请注意,它没有调用wrapped
,只是返回了它。您将需要致电x
来更改此行为:
x()
10
# Which is implicitly calling wrapped() to return 10
装饰器语法会为您解决此问题:
def f(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper # still returns an un-called function
@f
def x():
return 10
x()
# 10
@f
将有效执行f(x())
的地方。因为您没有调用该函数,所以您永远无法获得返回的类型,因此int
会引发一个TypeError
。
在您的示例中明确地:
def wrapper():
print("wrapper")
def wrapped():
print("wrapped")
return "1" # you need to return a value here, otherwise it will return None
return wrapped
int(wrapper()())
# wrapper
# wrapped
# 1
请注意,在调用wrapper
之后,多余的括号被称为wrapped
。另外,如果您没有从wrapped
返回值,那么您将返回None
,这将引发一个不同的TypeError: int() argument must be a string, a bytes-like object or a number, not 'NoneType'