1

这个问题不是关于解决问题,而是关于理解 Python (2.7) 编译器部分的内部工作原理。

请参阅下面的代码。它是一个标准的装饰器函数,其参数去掉了所有花哨的东西。

def deco(basedir):
  def wrap(f):
    def newf(*args, **kwargs):
      if basedir == "":          # local or nested?
        basedir="empty"          # local scope
      print basedir              # local or nested?
      return f(*args, **kwargs)
    return newf
  return wrap

@deco(basedir="full")
def test1(a):
  print a

if __name__ == "__main__":
  test1("test1")

当您对其进行测试时,它会失败并出现 UnboundLocalError: local variable 'basedir' referenced before assignment on the if basedir == "":行。请注意,在此示例中,条件(赋值)的主体从未执行过。

但是,当您将 if 替换为以下代码片段时,它突然起作用了。

if basedir == "":
  base = "empty"
else:
  base = basedir
print base

当解释器遇到分配时,我希望失败的情况会创建一个局部变量 basedir,但在 if 语句中使用父级的范围。但在我看来,当代码中的任何地方存在basedir=赋值时,它也会尝试在 if 中使用局部变量。

那么有人可以向我解释一下 Python 编译器在这种情况下是如何创建名称的吗?本地范围是否在编译时提前准备好?当编译器看到对局部变量的赋值时,它是否使用未定义的值预初始化名称?

你知道这种行为是否记录在任何地方吗?

我知道以前在这里解决了类似的情况,但我不是在解决之后。我想看看解释,最好是指向文档的指针。

相关: “赋值前引用的局部变量”——只有函数?

4

2 回答 2

0

问题是 Python 编译器无法确定basedir' 的正确范围。Python 中的作用域是静态确定的。但是basedir="empty"赋值语句使basedir变量成为newf函数的局部变量。因此,您无法在首次分配之前访问局部变量。

至于你的“修复”,你只是删除了分配,basedir="empty"并且basedir不是更本地的,newf但它使用 fromdeco函数。

于 2013-09-10T14:43:38.453 回答
0

在 Python 2 中,您只能全局或本地设置变量,不能嵌套:

global_variable_that_is_global = 1
global_variable_that_is_only_used_locally = 2

def function():
    nested_variable_that_can_not_be_set_by_inner_functions = 3
    def inner_function():
        global global_variable_that_is_global
        global_variable_that_is_global = "changed"
        global_variable_that_is_only_used_locally = "changed"
        nested_variable_that_can_not_be_set_by_inner_functions = "changed"

    def get_nested_variable():
        return nested_variable_that_can_not_be_set_by_inner_functions

    return inner_function, get_nested_variable

当您执行此操作时,您可以尝试一下:

>>> inner_function, get_nested_variable = function()
>>> get_nested_variable()
3
>>> inner_function()
>>> get_nested_variable()
3
>>> global_variable_that_is_only_used_locally
2
>>> global_variable_that_is_global
'changed'

因此,与 Python 2 相比,Python 3 中有一个 nonlocal 关键字:

>>> def function():
    nonlocal_variable = 1
    def inner_function():
        nonlocal nonlocal_variable
        nonlocal_variable = "changed"
    def get_nonlocal_variable():
        return nonlocal_variable
    return inner_function, get_nonlocal_variable

>>> inner_function, get_nonlocal_variable = function()
>>> get_nonlocal_variable()
1
>>> inner_function()
>>> get_nonlocal_variable()
'changed'
于 2013-09-10T15:17:32.240 回答