python,装饰和封闭混淆

Yue*_*oum 4 python closures decorator

我有一些测试代码:

def num(num):
    def deco(func):
        def wrap(*args, **kwargs):
            inputed_num = num
            return func(*args, **kwargs)
        return wrap
    return deco


@num(5)
def test(a):
    return a + inputed_num

print test(1)

运行此代码时,我得到一个错误,表明未定义 'inputed_num'

我的问题是:在wrap函数中,是不是func可以得到'inputed_num'的闭包?

无论如何,如果没有,我该如何实现我的目标: 初始化一些值,并在main函数中直接使用该值.

想.

Ray*_*ger 6

我的问题是:在wrap函数中,是不是func可以得到'inputed_num'的闭包?

对不起,这不是装饰工作的方式.它们最初定义函数应用.到那时,为时已晚.

当你写:

@num(5)
def test(a):
    return a + inputed_num
Run Code Online (Sandbox Code Playgroud)

这相当于:

def test(a):
    return a + inputed_num

test = num(5)(test)       # note that num(5) is called after test() is defined.
Run Code Online (Sandbox Code Playgroud)

为了实现您的目标,让inputed_num成为第一个要测试的参数.然后,让装饰器传入该参数:

def num(num):
    def deco(func):
        def wrap(*args, **kwargs):
            inputed_num = num
            return func(inputed_num, *args, **kwargs)  # this line changed
        return wrap
    return deco

@num(5)
def test(inputed_num, a):                              # this line changed
    return a + inputed_num

@num(6)
def test2(inputed_num, a):
    return a + inputed_num

print test(10)   # outputs 15
print test2(10)  # outputs 16
Run Code Online (Sandbox Code Playgroud)

希望为你清除一切:-)


Bre*_*arn 6

不,没有这样的封闭.函数可以关闭周围词汇上下文中存在的变量,而不是调用上下文中的变量.换句话说,如果您实际上在另一个函数中编写了一个函数,那么内部函数可以访问外部函数中的变量:

def f():
    g = 2
    def f2():
        print g
    f2()
Run Code Online (Sandbox Code Playgroud)

但函数永远不能访问调用它们的函数内的变量.

一般来说,没有办法做你想做的事情,即在函数外部设置函数中的任意变量.最接近的是你可以global inputed_num在装饰器中使用a inputed_num作为全局变量.然后test将访问全局值.

def num(num):
    def deco(func):
        def wrap(*args, **kwargs):
            global outsider
            outsider = num
            return func(*args, **kwargs)
        return wrap
    return deco
@num(5)
def test(a):
    print a+outsider

>>> test(2)
7
Run Code Online (Sandbox Code Playgroud)

但是,当然变量设置是全局的,因此多个并发使用(例如,递归)将不起作用.(只是为了好玩,你也可以在这里看到一个非常神秘的方法来做到这一点,但是在现实世界中对它有用太疯狂了.)