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 __()调用只是为了测试一下,但我总是得到同样的错误。
答案 0 :(得分:2)
您的代码存在一些问题。
super().__init__
并没有按照您的想法行事。每次调用__init__
时,您基本上都会在Point.__init__
范围内运行tri
。如果您print(tri)
,您会发现tri
同时具有x
和y
属性。
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
继承。继承扩展了定义。
在Triangle
和Point
的情况下,您实际想要的代码(在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