所以我有这段代码:
def collect_input(func):
"""
A decorator which adds an all_input attribute to the wrapped function.
This attribute collects any input passed to the function.
"""
def wrapper(*args, **kwargs):
wrapper.all_input.append(*args)
return func(*args, **kwargs)
wrapper.all_input = []
return wrapper
@collect_input
def foo(bar):
print('in foo')
foo(5)
foo('spam')
print(foo.all_input)
我的问题是:如果在foo.all_input
范围内宣布collect_input
,为什么可以访问private boolean sendImage(byte[] imageData, InetAddress address,
int port) throws UnknownHostException, SocketException {
boolean ret = false;
DatagramSocket socket = null;
try {
socket = new DatagramSocket();
DatagramPacket dp = new DatagramPacket(imageData, imageData.length, address, PUERTO_UDP);
socket.send(dp);
ret = true;
} catch (IOException e) {
Main.lanzarExcepcion(e);
ret = false;
} finally {
if (socket != null) {
socket.close();
}
}
return ret;
}
?
答案 0 :(得分:2)
Python的优点在于它有一组规则来处理它的对象,并且这些规则的例外情况很少。
在这种情况下,装饰的函数只是一个普通的Python对象。一个恰好也可以调用。
在collect_input里面的行wrapper.all_input = []
中发生的是它在对象上设置了一个属性 - 在那个名为wrapper
的点 - 但是它将被返回并代替foo
在全局范围内起作用。这就是装饰者的工作方式。
让我们一步一步地让它尽可能清晰:
运行上面的代码时,它定义了collect_input
函数 - 它被设计用作装饰器。
然后定义foo
函数,但在将其添加到全局范围之前,它会传递到collect_input
函数。这就是" @"语法呢。在它存在之前,装饰函数的方法是首先定义一个函数,然后用正常赋值将它替换为装饰器的返回值。所以,上面的代码与:
def foo(...): ...
foo = collect_input(foo)
在" collect_input"中,将在新foo
函数内调用原始wrapper
func。这个wrapper
函数:每次调用装饰器collect_input
时创建的新(函数)对象是取代最外foo
定义的对象。您可以在wrapper
的代码中看到有额外的代码来完成collect_input
的意图:在列表中注释输入参数,附加到自身然后恢复对原始的调用函数 - 在这种情况下为foo
。
最后wrapper
返回的collect_input
对象取代foo
,但在装饰器调用中附加了all_inputs
列表。因此,它可以作为foo
对象的属性在全局范围内访问 - 无论它在何处定义。请注意,您无法在函数外部使用名称func
或wrapper
,如预期的那样。
答案 1 :(得分:1)
@collect_input
def foo(bar):
print(foo.__name__) # wrapper
print('in foo')
您可以看到wrapper
取代foo