功能属性 - 范围

时间:2016-12-01 10:45:42

标签: python function scope attributes decorator

所以我有这段代码:

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; }

2 个答案:

答案 0 :(得分:2)

Python的优点在于它有一组规则来处理它的对象,并且这些规则的例外情况很少。

在这种情况下,装饰的函数只是一个普通的Python对象。一个恰好也可以调用。

在collect_input里面的行wrapper.all_input = []中发生的是它在对象上设置了一个属性 - 在那个名为wrapper的点 - 但是它将被返回并代替foo在全局范围内起作用。这就是装饰者的工作方式。

让我们一步一步地让它尽可能清晰:

  1. 运行上面的代码时,它定义了collect_input函数 - 它被设计用作装饰器。

  2. 然后定义foo函数,但在将其添加到全局范围之前,它会传递到collect_input函数。这就是" @"语法呢。在它存在之前,装饰函数的方法是首先定义一个函数,然后用正常赋值将它替换为装饰器的返回值。所以,上面的代码与:

    相同

    def foo(...):     ...

    foo = collect_input(foo)

  3. 在" collect_input"中,将在新foo函数内调用原始wrapper func。这个wrapper函数:每次调用装饰器collect_input时创建的新(函数)对象是取代最外foo定义的对象。您可以在wrapper的代码中看到有额外的代码来完成collect_input的意图:在列表中注释输入参数,附加到自身然后恢复对原始的调用函数 - 在这种情况下为foo

  4. 最后wrapper返回的collect_input对象取代foo,但在装饰器调用中附加了all_inputs列表。因此,它可以作为foo对象的属性在全局范围内访问 - 无论它在何处定义。请注意,您无法在函数外部使用名称funcwrapper,如预期的那样。

答案 1 :(得分:1)

@collect_input
def foo(bar):
    print(foo.__name__) # wrapper
    print('in foo')

您可以看到wrapper取代foo

的方式