Python closure function losing outer variable access

前端 未结 3 1155
时光取名叫无心
时光取名叫无心 2021-02-19 07:36

I just learned python @ decorator, it\'s cool, but soon I found my modified code coming out weird problems.

def with_wrapper(param1):
    def dummy_wrapper(fn):
         


        
相关标签:
3条回答
  • 2021-02-19 07:44

    When Python parses a function, it notes whenever it finds a variable used on the left-hand side of an assignment, such as

    param1 = 'new'
    

    It assumes that all such variables are local to the function. So when you precede this assignment with

    print param1
    

    an error occurs because Python does not have a value for this local variable at the time the print statement is executed.


    In Python3 you can fix this by declaring that param1 is nonlocal:

    def with_wrapper(param1):
        def dummy_wrapper(fn):
            nonlocal param1
            print param1
            param1 = 'new'
            fn(param1)
        return dummy_wrapper
    

    In Python2 you have to resort to a trick, such as passing param1 inside a list (or some other mutable object):

    def with_wrapper(param1_list):
        def dummy_wrapper(fn):
            print param1_list[0]
            param1_list[0] = 'new'   # mutate the value inside the list
            fn(param1_list[0])
        return dummy_wrapper
    
    def dummy():
        @with_wrapper(['param1'])   # <--- Note we pass a list here
        def implementation(param2):
            print param2
    
    0 讨论(0)
  • 2021-02-19 07:58

    Handy for temporary situations or exploratory code (but otherwise not good practice):

    If you're wanting to capture a variable from the outer scope in Python 2.x then using global is also an option (with the usual provisos).

    While the following will throw (assignment of outer1 within inner makes it local and hence unbounded in the if condition):

    def outer():
        outer1 = 1
        def inner():
            if outer1 == 1:
                outer1 = 2
                print('attempted to accessed outer %d' % outer1)
    

    This will not:

    def outer():
        global outer1
        outer1 = 1
        def inner():
            global outer1
            if outer1 == 1:
                outer1 = 2
                print('accessed outer %d' % outer1)
    
    0 讨论(0)
  • 2021-02-19 08:02

    You assign param1 in the function, which makes param1 a local variable. However, it hasn't been assigned at the point you're printing it, so you get an error. Python doesn't fall back to looking for variables in outer scopes.

    0 讨论(0)
提交回复
热议问题