簡體   English   中英

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 的那一行。 這里有什么明顯的錯誤嗎? 我嘗試將 self 和其他測試參數添加到 super().__init__() 調用中只是為了測試一下,但我總是得到同樣的錯誤。

您的代碼存在一些問題。

super().__init__沒有做你認為的那樣。 在每次調用__init__您實際上是在tri的范圍內運行Point.__init__ 如果你print(tri)你會看到trixy屬性。

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)

現在你有了一個工作示例,但你仍然可以做得更好。 看到您在Triangle中使用的Point的唯一部分是__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等。

你的問題不是真正的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一個實例,根據我的小生物學背景是不正確的。

當你被召喚時

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

它調用 Point 類的__init__()方法,但不返回 Point 的實例,它返回 None (並將 x,y 屬性添加到 Triangle 類的tri實例中)。

用 3 Points 實例化 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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM