我正在尝试使用基于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
此错误的原因是什么?如何解决此问题?
答案 0 :(得分:1)
用Python(或其他语言)嵌套类很少有意义。在这种情况下,它根本没用。
如果在"外面"你希望有一个关联的" Inner"的实例,应该在外部的__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代码中的一种约定,开发人员通常会知道他们不应该信任以单个_
开头的任何类,函数或其他名称,以便在第三方代码中安全使用 - 这是最接近的Python进入"私有"或者"受保护的"成员。
现在,走到界限:
...
self.x = super(Inner, self).__init__
这再次毫无意义。 super
或显式引用超类意味着调用超类 - 即您继承的类。您在代码中没有创建继承关系,而是在组合中创建了一个继承关系。这就是您收到错误消息的原因 - 如果您使用的是super的显式版本,则您传递的对象必须是您正在调用super
的类的子类。而事实并非如此。 (另外,以这种形式进行,它不会调用方法 - 只是引用它 - 所有函数或方法调用都是通过使用()
来调用的)
你也可以从内部进行外部继承 - 在这种情况下,外部将会"成为"一个内部,不需要在一个属性中保持对它的引用 - self
将意味着一个外层和一个内部类。
在这种情况下,我们需要引用" Inner"在解析" Outer"的声明时,需要先定义它:
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的参数可以是显式的,并且调用将是{{ 1}}。
(再次,调用它super(Outer, self).__init__()
将意味着您的类的用户不应该继承或实例化_Inner
并且应该使用_Inner
- 这是编码风格的惯例而不是语言语法)