how to use outer variable in inner method

214 views
Skip to first unread message

贾晓磊

unread,
May 21, 2012, 2:50:07 AM5/21/12
to python-...@googlegroups.com
hi,all:

when i use tornado.uwe.asynchronous, i wrote a slice as below:

    @authenticated
    @tornado.web.removeslash
    @tornado.web.asynchronous
    def put(self):
        status = ErrorCode.SUCCESS
        try:
            name = 'jia'
            data = DotDict(json_decode(self.request.body))
            key = data.car_sets['key']
            value = data.car_sets['value']
            print 'outer_dir()', dir() 
        except Exception as e:
            logging.exception("Set terminal failed. Exception: %s", e.args)
            status = ErrorCode.SERVER_BUSY
            self.write_ret(status)
            IOLoop.instance().add_callback(self.finish)
            return

        def _on_finish(response):
            print 'inner_dir()', dir() 
            status = ErrorCode.SUCCESS
            print 'test name', name           
            response = json_decode(response)
            print 'res', response
            if True: #response['success'] == 0:
                sql_cmd = 'UPDATE T_TERMINAL_INFO_W SET ' + key + ' = %s'
                print 'sql_cmd', sql_cmd
                self.db.execute(sql_cmd, value)
            else:
                status = ErrorCode.SERVER_BUSY
            self.write_ret(status)
            IOLoop.instance().add_callback(self.finish)

        args = DotDict(seq=SeqGenerator.next(self.db),
                       cid=self.current_user.cid)
        args[key] = value

        GFSenderHelper.async_forward(GFSenderHelper.URLS.TERMINAL, args,
                                          _on_finish)

then, we can get the output:


outer dir ['self', 'status','name','data','key','value']

inner dir ['self', 'response']

if we delete ' status = ErrorCode.SUCCESS' in _on_finish(), we will encounter with below:

 UnboundLocalError: local variable 'status' referenced before assignment

now, my question is :
why in _on_finish method, i can not use the 'status' defined in put method??


# NOTE: 

we all know that: in python, the inner method can invoke the variable defined in outer method easily.

def test_out():
    name = 'jia'
    age = 20
    status = 0
    print 'outer_dir', dir()
    
    def test_inner():
        name = 'jiaxiaolei'
        print name , age, status
        print 'dir', dir() 
    test_inner()
        
test_out()

# output:
outer_dir ['age', 'name', 'status']
dir ['age', 'name', 'status']

any response will be appreciated.

-- Jia Xiaolei 




Alek Storm

unread,
May 21, 2012, 3:47:38 AM5/21/12
to python-...@googlegroups.com
This mistake can bite even experienced Python users. When a closure is created, variables are only inherited from the enclosing scope if they are not masked. If you assign to a variable *anywhere* within the closure, Python considers that variable to "belong" to that closure - the variable of the same name in the enclosing scope is masked.

In your code (the version with the `status = ErrorCode.SUCCESS` line deleted), even though the `status = ErrorCode.SERVER_BUSY` line is never executed, its presence causes the `status` variable to be masked. The bad news is that, unless you're using Python 3.x (which has the `nonlocal` keyword), there is no non-kludgy solution. I recommend making `status` a one-element list, and assigning to `status[0]` instead.

Alek

贾晓磊

unread,
May 21, 2012, 10:32:50 AM5/21/12
to python-...@googlegroups.com
thanks for Alek.
after read your email, i read some stuff about python closure and  know the reason the problem i mentioned before.

now, maybe we can have a good think after reading below:

part 1: 

def test_out():
    name = 'jia'
    age = 20
    status = 0
    print 'outer_dir', dir()

    def _test_inner(flag):
        print 'in dir', dir()
        if not flag:

            name = 'jiaxiaolei'
        print name , age, status
    _test_inner(False)
    _test_inner(True)

test_out()

# the output:
outer_dir ['age', 'name', 'status']
in dir ['age', 'flag', 'status']
jiaxiaolei 20 0
in dir ['age', 'flag', 'status']
Traceback (most recent call last):
  File "test_closure.py", line 15, in <module>
    test_out()
  File "test_closure.py", line 13, in test_out
    _test_inner(True)
  File "test_closure.py", line 11, in _test_inner

    print name , age, status
UnboundLocalError: local variable 'name' referenced before assignment

part 2: 
def test_out():
    name = 'jia'
    age = 20
    status = 0
    print 'outer_dir', dir()

    def _test_inner(flag):
        print 'in dir', dir()
        #if not flag:
        #    name = 'jiaxiaolei'

        print name , age, status
    _test_inner(False)
    _test_inner(True)

test_out()

# output: 
outer_dir ['age', 'name', 'status']
in dir ['age', 'flag', 'name', 'status']
jia 20 0
in dir ['age', 'flag', 'name', 'status']
jia 20 0

thanks again. wish you good luck.

-- Jia Xiaolei
--
NAME: 贾晓磊/Jia Xiaolei
MOBILE: 13011292217
QQ: 281304051

Reply all
Reply to author
Forward
0 new messages