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
同时具有 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
的 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= 的对象] 具有额外的属性。继承扩展定义。
在 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)
使用另一个 class 作为属性不会强制您继承它。在上面的例子中,你告诉 Python 任何 Animal
也是 Plant
的一个实例,根据我的小生物学背景,这是不正确的。
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
同时具有 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
的 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= 的对象] 具有额外的属性。继承扩展定义。
在 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)
使用另一个 class 作为属性不会强制您继承它。在上面的例子中,你告诉 Python 任何 Animal
也是 Plant
的一个实例,根据我的小生物学背景,这是不正确的。