【问题标题】:How can an outer class access data from its inner class?外部类如何从其内部类访问数据?
【发布时间】:2018-02-20 21:59:30
【问题描述】:

我试图通过基于this question/answer 的非常简单的测试用例来更好地理解如何使用子类。

class Outer():

    def __init__(self, x):
        self.x = super(Inner, self).__init__
        # self.x = Inner(**kwargs)

    def add_two(self):
        """ """
        return self.x + 2

    class Inner():

        def __init__(self, x=2):
            self.x = x

res = Outer(x=3).add_two()
# res = Outer({'x' : 3}).add_two()
print(res)
>> NameError: name 'Inner' is not defined

如果我运行相同的代码但将 Inner() 设为自己的单独类(而不是 Outer() 的子类,我会收到以下错误。

TypeError: super(type, obj): obj must be an instance or subtype of type

此错误的原因是什么,我该如何解决?

【问题讨论】:

  • Inner 是类的一个属性 - 所以它必须被称为self.Inner。不确定super 在这里是否正确 - 您可能只是想实例化它。
  • (去掉“元类”标签,因为这里没有涉及到元类的使用,甚至不解释发生了什么)

标签: python-3.x class oop subclass


【解决方案1】:

在 Python(或其他语言)中嵌套类很少有意义。在这种情况下,它根本没有任何用处。

如果您希望在“Outer”类上拥有“Inner”的关联实例,则应在 Outer 的 __init__ 方法上将其创建为实例属性 - 如下所示:

class Outer():

    def __init__(self, x):
        self.x = Inner(x)
        # self.x = Inner(**kwargs)

    def add_two(self):
        """ """
        return self.x + 2


class Inner():

    def __init__(self, x=2):
        self.x = x

现在,逐步查看您的原始代码,并尝试更好地理解它为什么不起作用: 在 Python 中,类主体中声明的所有内容都成为该类的属性——它的一个副本将(通常)由该类的所有实例共享。声明一个嵌套的整个类在语法上是合法的,但不会给你带来任何好处:内部类在任何意义上都不会被语言从外部世界“隐藏”起来:不是被语言,也不是被 Python 开发人员通常遵循的约定。

如果您希望用户(即其他程序员,或使用此文件的代码中的您自己)创建“Outer”实例并避免创建“Inner”实例,只需在其名称前加上 _ .这是 Python 代码中的约定,开发人员通常会知道,他们不应该相信任何以单个 _ 开头的类、函数或其他名称可以安全地用于第 3 方代码 - 这是最接近 Python 的“私人”或“受保护”成员。

现在,开始吧:

    ...
    self.x = super(Inner, self).__init__

这又是没有意义的。 super 或显式引用超类意味着调用超类 - 即您继承的类。您在代码中没有创建继承关系,而是创建了一种组合关系。这就是您收到该错误消息的原因 - 如果您使用的是 super 的显式版本,则您传递的对象必须是您正在调用 super 的类的子类。而这里的情况并非如此。 (另外,以这种形式执行,它不调用方法 - 只是引用它 - 所有函数或方法调用都是通过使用()来完成的)

您也可以让 Outer 从 Inner 继承 - 在这种情况下,Outer 将“成为”一个 Inner,无需在属性中保留对它的引用 - self 将意味着 Outer 和 Inner 类。 在这种情况下,我们在解析“Outer”的声明时需要引用“Inner”,所以需要先定义:

class _Inner():

    def __init__(self, x=2):
        self.x = x

class Outer(_Inner):

    def __init__(self, x):
        super().__init__(x)

    def add_two(self):
        """ """
        return self.x + 2

注意使用无参数super - 这是Python 3 的主要变化之一。如果您需要编写仍然与Python 2 兼容的代码,super 的参数可以是显式的,调用将是super(Outer, self).__init__()

(同样,将其称为 _Inner 意味着您的类的用户不应继承或实例化 _Inner,而应使用 Outer - 这是编码风格而非语言语法的约定)

【讨论】:

    猜你喜欢
    • 2011-01-02
    • 2011-02-13
    • 2021-03-13
    • 2021-12-31
    • 1970-01-01
    • 1970-01-01
    • 2014-02-11
    • 1970-01-01
    相关资源
    最近更新 更多