嵌套类中的模块的意外UnboundLocalError

时间:2013-12-16 20:44:39

标签: python closures local-variables

我继承了一个遗留单元测试,试图覆盖嵌套在另一个类中的自定义类的名称datetime。我现在正在重构它(我同意这非常糟糕)但我不明白我所看到的特定错误。

我看到了一个UnboundLocalError,我可以通过一个自包含的示例重现这一点:

import datetime
class Foo(object):

    def inner_scope(self):

        real_datetime = datetime
        class datetime(datetime.datetime):
            @staticmethod
            def convert():
                return "blah"

        x = datetime(2012, 1, 1)
        y = x.convert()
        return x, y

f = Foo()
f.inner_scope()

我明白了:

In [439]: f.inner_scope()
---------------------------------------------------------------------------
UnboundLocalError                         Traceback (most recent call last)
<ipython-input-439-c5053fb49b64> in <module>()
----> 1 f.inner_scope()

<ipython-input-437-222b3997ec2c> in inner_scope(self)
      3     def inner_scope(self):
      4
----> 5         real_datetime = datetime
      6         class datetime(datetime.datetime):
      7             @staticmethod

UnboundLocalError: local variable 'datetime' referenced before assignment

我已经尝试添加print语句来立即打印type(datetime)type(datetime.datetime)在类定义内部(这可行)并且紧接在inner_scope定义内部(这失败)。

凭借闭包,datetime的值不应该由导入的模块提供,因为在inner_scope函数中检查范围越来越高?< / p>

据我所知,我也没有尝试修改它,因为我已经看到了其他UnboundLocalError有关修改变量的问题,这些变量可以通过闭包访问但不会更改,除非首先作为局部变量。

1 个答案:

答案 0 :(得分:2)

此案例与您见过的与UnboundLocalError相关的其他案例没有什么不同。由于您的内部类也被称为datetime,Python的字节码编译器会将名称datetime标记为局部变量。由于您尝试在类声明之前分配real_datetime = datetime,因此会收到错误。

如果您考虑

,这可能会更清楚
class datetime(datetime.datetime):
    ...

是对以下内容的等效声明:

datetime = type('datetime', (datetime.datetime), {...class members...})

作为此类事情的解决方法,您可以始终使用datetime的其他名称作为模拟类。它可能与它的名称无关(如果它确实很重要,你仍然可以通过在创建类之后分配给它的__name__属性来覆盖它。

在Python 3中,您只需声明nonlocal datetime就像任何其他非局部变量一样。