python,在装饰和closu中混淆

2024-04-20 04:17:39 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一些测试代码:

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是否没有一个闭包可以得到“inputten num”?在

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

思考。在


Tags: 函数代码testreturndef错误argsnum
3条回答

不,没有那样的结局。在上下文中调用不在上下文中的函数。换句话说,如果你真的把一个函数写成另一个函数,那么内部函数可以访问外部函数中的变量:

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

但是函数永远不能访问调用它们的函数内部的变量。在

一般来说,没有一种方法可以做你想做的,也就是说,从函数外部设置一个函数中的任意变量。最接近的是可以在decorator中使用global inputed_numinputed_num指定为全局变量。然后test将访问全局值。在

^{pr2}$

但当然,变量设置是全局的,所以多个并发使用(例如递归)将不起作用。(只是为了好玩,您还可以看到here找到一种非常神秘的方法来实现这一点,但它太疯狂了,无法在真实世界中使用。)

正如@Raymond所说-decorators是在函数定义之后应用的。这意味着,在编译函数体本身时,Pythn会看到inputed_num变量,因为它是一个本地定义的变量,所以它生成代码来尝试将其作为全局变量访问。在

这意味着你可以在你的装饰师那里解决它: decorator可以在函数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

以及:

^{pr2}$

My question is: In wrap function, is there not a closure that func can got 'inputed_num' ?

对不起,装修工不是这样工作的。它们在函数初始定义后被应用于。到那时,已经太晚了。在

当你写:

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

相当于:

^{pr2}$

为了实现您的目标,让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

希望能为你澄清一切:-)

相关问题 更多 >