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

时间:2018-02-14 12:23:29

标签: python python-3.x superclass

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 __()调用只是为了测试一下,但我总是得到同样的错误。

3 个答案:

答案 0 :(得分:2)

您的代码存在一些问题。

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类的新对象,并将该对象分配给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)

现在你有一个有效的例子,但你仍然可以做得更好。看作Point中使用Triangle的{​​{1}}的唯一部分是__new__我们为什么要从班级继承?在这种情况下,我会删除继承,只是创建新实例而不调用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等。

答案 1 :(得分:2)

这里的问题不是super,而是继承。

如果A的对象实际上被定义为具有额外属性的B对象,则类A应该从类B继承。继承扩展了定义。

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)

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

答案 2 :(得分:1)

当你被召唤时

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

它调用Point类的__init__()方法,但不返回Point的实例,它返回None(并将x,y属性添加到Triangle类的tri实例中)。

使用3点代码实例化Triangle代码可能如下所示:

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