4

我有一些测试代码:

定义数(数):
    定义装饰(功能):
        def wrap(*args, **kwargs):
            输入的_num = num
            返回函数(*args,**kwargs)
        返回包装
    返回装饰


@数字(5)
定义测试(一):
    返回一个 + input_num

打印测试(1)

运行此代码时,我收到一个错误,显示未定义“inputed_num

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

无论如何,如果没有,我该怎么做才能达到我的目的: 初始化一些值,并直接在主函数中使用这个值。

认为。

4

4 回答 4

6

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

抱歉,这不是装饰器的工作方式。它们在函数最初定义后被应用。到那时,为时已晚。

当你写:

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

这相当于:

def test(a):
    return a + inputed_num

test = num(5)(test)       # note that num(5) is called after test() is defined.

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

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

希望这能为你清除一切:-)

于 2012-09-13T03:12:38.497 回答
6

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

def f():
    g = 2
    def f2():
        print g
    f2()

但是函数永远无法访问调用它们的函数内部的变量。

一般来说,没有办法做你想做的事,即从函数外部在函数中设置任意变量。最接近的是您可以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

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

于 2012-09-13T03:16:47.083 回答
3

正如@Raymond 所说 - 在定义函数后应用装饰器。这意味着在编译函数体本身时,Pythn 会看到该inputed_num变量,并且当它嗅探本地定义的变量时,它会生成代码以尝试将其作为全局变量来访问。

这意味着您可以在您的装饰器中解决它:您的装饰器可以在函数 globals() 空间中设置一个具有所需名称的全局变量,然后调用该函数。它应该在单线程代码中可靠地工作:

def num(num):
    def deco(func):
        def wrap(*args, **kwargs):
            glob = func.func_globals
            marker = object()
            original_value = glob.get("inputed_num", marker)
            glob["inputed_num"] = num
            result = func(*args, **kwargs)
            if original_value is marker:
                del glob["inputed_num"]
            else:
                glob["inputed_num"] = original_value
            return result
        return wrap
    return deco


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

和:

>>> print test(1)
6
于 2012-09-13T03:22:21.350 回答
1

这不是装饰器应该使用的方式,我认为您的目的可能是这样做的

def outwrapper(n):
    def wrapper(func):
        def f(*args, **argw):
            return n + func(*args, **argw) 
        return f
    return wrapper 


@outwrapper(4)
def test(n):
    return n


print test(1) 
于 2012-09-13T03:20:31.560 回答