【问题标题】:Variable not found in the outer class scope在外部类范围内找不到变量
【发布时间】:2013-10-24 07:49:41
【问题描述】:

我有这个代码:

class Attributes(object):
    class __metaclass__(type):
        def __init__(self, cls_name, cls_bases, cls_dict):
            # super(Attributes.__metaclass__, self) # NameError: global name 'Attributes' is not defined
            super(__metaclass__, self).__init__(
                cls_name, cls_bases, cls_dict)

给予

NameError: global name '__metaclass__' is not defined

为什么在外部范围内找不到__metaclass__ 变量?

【问题讨论】:

  • 你能给我更多的代码来处理,这样我就可以快速运行它,看看我是否能重现问题?
  • 我已经尝试重现该问题,但事实证明,您不能在具有调用 super 的 init 方法的类中拥有类。它不仅仅是第 3 级继承,即使您尝试在 Attributes 内部调用 super,它也不起作用。您需要致电SimpleModel.Attributes 来获取它。

标签: python class namespaces


【解决方案1】:

试试这个

super(Attributes.__metaclass__, self).__init__(cls_name, cls_bases, cls_dict)

【讨论】:

  • 感谢您的解决方法。我做了一个不同的解决方法,将有问题的类放在模块的顶层。
  • 我已经简化了问题中的示例。如果你尝试使用super(Attributes.__metaclass__, self) - 你会得到NameError: global name 'Attributes' is not defined。所以你的解决方案不起作用。
  • Warwaruk 是对的。在创建元类的第一个实例时,Attributes 还不存在:首先创建元类,然后在外部类完成之前立即(自动)创建一个实例。
【解决方案2】:

创建类时,只有其名称可见。在类创建完成之前,它的内容还不存在。因此,类中的部分在创建期间不能访问类的任何字段。因此,您将需要使用完全限定名称来表示您要访问该类的字段

您当前正在创建一个类SimpleModel,同时您正在创建一个类Attributes,同时创建一个类__metaclass__。因为当你这样做时,SimpleModel 类还不存在,__init__ 方法还不是任何存在的一部分。它首先被创建,然后将成为__metaclass__ 类的一部分。因此它不能知道标识符__metaclass__。而且由于__metaclass__ 也永远不会成为全局变量,因此在调用时,无法知道此标识符。

这就是为什么此时您的作用域中没有__metaclass__,但是当稍后调用__init__ 时,全局作用域中只有SimpleModel 可用,因此您可以在其上命名: SimpleModel.Attributes.__metaclass__.

【讨论】:

  • __init__ 内部不仅已经创建了类,而且还创建了它的实例并将其作为self 传递。在这种情况下,self 是一个类,它是其元类的实例。
  • @warwaruk:你说的是运行时,我说的是编译时间(可以这么说,如果可以在 Python 中真正将两者分开的话)。当__init__编译 时,这些类还不存在。这就是 Python 不允许在没有完全限定名称的情况下引用本地类的根本原因。问题:我应该在回答中详细说明这方面吗? (我在第二段中添加了一个(希望)澄清句。)请注意,我谈论的是“创建一个类”,而不是“创建一个实例”......
  • 我在运行时得到了引用的异常,因为在 Attributes 类完全定义之后,它是通过调用 Attributes.__metaclass__s __new____init__ 创建的。创建一个类意味着创建它的元类的一个实例。我认为你错了。
  • 我想你可能会对这种结构感到困惑:class __metaclass__(AttributesMeta) 实际上等同于__metaclass__ = AnotherAttributeMetaclass,其中AnotherAttributeMetaclass 将在前面定义为与问题中__metaclass__ 类的相同主体.另见stackoverflow.com/questions/100003/…
  • 当然你会在运行时遇到异常。但是因为在编译期间标识符是未知的。关于如何在我的回答中更清楚地提出任何建议?
【解决方案3】:

看起来答案是这样的:

方法的外部作用域不是类主体,而是包含该类或模块的外部函数。

这就是为什么

class Test():
    attr_1 = 'smth'
    def a_method(self):
        attr_1  # not visible on this line

attr_1 在方法 Test.a_method 中不可见

解决方案是在全局级别定义元类:

class AttributesMeta(type):
    def __init__(self, cls_name, cls_bases, cls_dict):
        super(__metaclass__, self).__init__(
            cls_name, cls_bases, cls_dict)

class Attributes(object):
    __metaclass__ = AttributesMeta

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-08-18
    • 2011-06-01
    • 2019-10-05
    • 1970-01-01
    • 2018-11-30
    • 2017-12-02
    • 2022-01-05
    • 1970-01-01
    相关资源
    最近更新 更多