Python - 调用 super() 作为子类的属性

Python - call super() as attribute of subclass

class Point(object):

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

class Triangle(Point):

    def __init__(self, v1, v2, v3):
        """Create a new Triangle with vertices (v1, v2, v3)."""
        self.v1 = super().__init__(x=v1[0], y=v1[1])
        self.v2 = super().__init__(x=v2[0], y=v2[1])
        self.v3 = super().__init__(x=v3[0], y=v3[1])

tri = Triangle((1,1),(1,10),(1,5))

我正在尝试调用 super().__init__() 作为子类的一个属性,但是当我执行上面的代码时,我收到一条错误消息:

__init__() missing 1 required positional argument: 'y'

指向子类中定义self.v1的那一行。这里有什么明显的错误吗?我已经尝试将自我和其他测试参数添加到 super().__init__() 调用只是为了测试一下,但我总是得到同样的错误。

当你被叫到时

self.v1 = super().__init__(x=v1[0], y=v1[1])

它调用 Point class 的 __init__() 方法,但 return 不是 Point 的实例,它 returns None(并添加x,y 属性到您的 tri 三角形实例 class).

用 3 点代码实例化三角形可能如下所示:

class Point(object):

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

class Triangle(object):

    def __init__(self, v1, v2, v3):
        """Create a new Triangle with vertices (v1, v2, v3)."""
        self.v1 = Point(x=v1[0], y=v1[1])
        self.v2 = Point(x=v2[0], y=v2[1])
        self.v3 = Point(x=v3[0], y=v3[1])

tri = Triangle((1,1),(1,10),(1,5))

     17         self.v1 = Point(x=v1[0], y=v1[1])
---> 18         self.v2 = Point(x=v2[0], y=v2[1])
     19         self.v3 = Point(x=v3[0], y=v3[1])

ipdb> self.v1
<__main__.Point object at 0x7f18c48da048>
ipdb> self.v1.x
1

您的代码存在一些问题。

super().__init__ 并没有按照您的想法行事。在每次调用 __init__ 时,您实际上是 运行 Point.__init__tri 的范围内。如果你 print(tri) 你会看到 tri 同时具有 xy 属性。

tri = Triangle((1,1),(1,10),(1,5))
print(tri.x)  # 1
print(tri.y)  # 5

你真正想要做的是为每个顶点创建一个 Point 的实例。要做到这一点并使用 super,您可以使用 self.v1 = super().__new__(x=v1[0], y=v1[1])__new__ 将构建 super 的 class 的新对象并将该对象分配给 self.v1.

class Triangle(Point):
    def __init__(self, v1, v2, v3):
        """Create a new Triangle with vertices (v1, v2, v3)."""
        self.v1 = super().__new__(x=v1[0], y=v1[1])
tri = Triangle((1,1),(1,10),(1,5))
print(tri.v1)  # Point (x=1, y=1
print(tri.v2)  # Point (x=1, y=10)

现在你有了一个工作示例,但你仍然可以做得更好。既然你在 Triangle 中使用的 Point 的唯一部分是 __new__ 为什么我们还要继承 class?在这种情况下,我将删除继承并只创建新实例而不调用 super().

此外,在 python 3 中,您不需要继承自 object

class Point():

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

class Triangle():

    def __init__(self, v1, v2, v3):
        """Create a new Triangle with vertices (v1, v2, v3)."""
        self.v1 = Point(x=v1[0], y=v1[1])
        self.v2 = Point(x=v2[0], y=v2[1])
        self.v3 = Point(x=v3[0], y=v3[1])

tri = Triangle((1,1),(1,10),(1,5))
print(tri.v1)  # Point (x=1, y=1
print(tri.v2)  # Point (x=1, y=10)

另外 - 我会推荐@Oliver 的实现。它更干净,不会创建那么多对象。唯一的副作用是将 v1 重命名为 x

你的问题不在于 super,而在于继承。

A class A 应该继承自 class B 如果 A 的对象实际上被定义为 [=14= 的对象] 具有额外的属性。继承扩展定义。

TrianglePoint 的情况下,您真正​​想要的代码,已经在 Alexander Kamyanskiy 和 Jim Wright 的回答中给出,不需要继承。此外,从数学上讲,三角形不是具有额外属性的点。

这是一个有意义的继承示例。

class Point:
    def __init__(self, x, y)
        self.x = x
        self.y = y

# A point in 3D really is a point in 2D with an extra coordinate
class Point3D(Point)
    def __init__(self, x, y, z):
        self.z = z
        super().__init__(x, y)

这是一个继承示例,虽然在编程上是正确的,但实际上并没有意义。

class Plant:
    def __init__(self, type):
        self.type= type

# Let me check my biology textbooks...
class Animal(Plant):
    def __init__(self, kind, favorite_food):
        self.kind = kind
        # Herbivores only please
        self.favorite_food = Plant(favorite_food)

使用另一个 class 作为属性不会强制您继承它。在上面的例子中,你告诉 Python 任何 Animal 也是 Plant 的一个实例,根据我的小生物学背景,这是不正确的。