使用try / except时Python中奇怪的变量范围

时间:2014-02-04 22:42:41

标签: python

foo = 'asdf'
bar = 'asdf'
foobar = 'asdf'

def test():
  def get_foo():
    print 'foo = ' + foo

  def get_bar():
    try:
      print 'bar = ' + bar
    except Exception as e:
      print 'nobody set bar :('

  def get_foobar():
    try:
      foobar
    except Exception as e:
      print e
      foobar = "nobody set foobar :("
    print foobar

  print 'trying to get foo'
  get_foo()

  print '\ntrying to get bar'
  get_bar()

  print '\ntrying to get foobar'
  get_foobar()

test()

当我运行时,我明白了:

trying to get foo
foo = asdf

trying to get bar
bar = asdf

trying to get foobar
local variable 'foobar' referenced before assignment
nobody set foobar :(

我设置了三个变量:foo,bar,foobar。然后,我使用三个嵌套函数打印出来:get_foo,get_bar和get_foobar。

get_foo只是打印foo get_bar打印bar并检查异常 get_foobar使用try-except来确保在打印之前设置foobar。

不知怎的,get_foobar失败了?!

2 个答案:

答案 0 :(得分:2)

将行global foobar添加到get_foobar()

的顶部

这告诉字节码编译器要使用全局作用域而不是本地来引用此函数中的变量。

分配隐式地将变量的范围更改为整个函数范围的本地。

字节码:

## code input (local)
def test():
    print foobar
    foobar = 2

## bytecode output
#
# 3           0 LOAD_FAST                0 (foobar)
#             3 PRINT_ITEM 
#             4 PRINT_NEWLINE
# 
# 4           5 LOAD_CONST               1 (2)
#             8 STORE_FAST               0 (foobar)
#            11 LOAD_CONST               0 (None)
#            14 RETURN_VALUE

## code input (global)
def test():
    global foobar
    print foobar
    foobar = 2

## bytecode output
#
# 4           0 LOAD_GLOBAL              0 (foobar)
#             3 PRINT_ITEM 
#             4 PRINT_NEWLINE 
#
# 5           5 LOAD_CONST               1 (2)
#             8 STORE_GLOBAL             0 (foobar)
#            11 LOAD_CONST               0 (None)
#            14 RETURN_VALUE

请注意LOAD_FASTSTORE_FAST代替LOAD_GLOBALSTORE_GLOBAL的使用情况。 Python dis module documentation有一个操作码列表供参考。

您可以使用此代码快速转储函数的字节码:

import compiler, dis
code = compiler.compile('''
def test():
    print foobar
    foobar = 2
''', '__main__', 'exec')
dis.dis(code.co_consts[1])

答案 1 :(得分:0)

Martijn Pieters称之为。因为您在函数内部对foobar进行了赋值,所以创建了一个新的本地变量foobar,但这发生在编译时而非运行时,这就是未初始化版本的原因foobar块中已存在try