首页 文章

python,装饰和封闭混淆

提问于
浏览
3

我有一些测试代码:

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'不是 defined

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

无论如何,如果没有,我该怎样做才能实现我的目标: Initialize some value, and use this value directly in the main function.

想 .

4 回答

  • 5

    我的问题是:在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成为第一个要测试的参数 . 然后,让装饰器传入该参数:

    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
    

    希望为你清除一切:-)

  • 6

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

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

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

    一般来说,没有办法做你想要的,即在函数外部设置函数中的任意变量 . 最接近的是你可以在装饰器中使用 global inputed_num 来将 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
    

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

  • 2

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

    这意味着您可以在装饰器中对其进行解决:您的装饰器可以在函数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
    
  • 0

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

    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)
    

相关问题