【问题标题】:Best way to represent structure where subclass is like a superclass with one object表示子类就像具有一个对象的超类的结构的最佳方法
【发布时间】:2019-12-16 17:27:13
【问题描述】:

我想表示一个类似于无序卡片组的结构(例如,在 Python 3.7 中),它具有可以将单张卡片视为一副卡片的属性。

class Deck:
    def __init__(self, cards, owner):
        self.owner = owner
        self.cards = cards


class Card(Deck):
    def __init__(self, number, suit, owner):
        self.number = number
        self.suit = suit
        super().__init__({self}, owner)

    def __eq__(self, other):
        return self.number == other.number and self.suit == other.suit and self.owner == other.owner

    def __hash__(self):
        return hash((self.number, self.suit, self.owner))


card = Card(5, 'clubs', 'me')

(以上返回AttributeError: 'Card' object has no attribute 'owner'

如果我想订购我的套牌,这很简单,因为Card.__init__() 只会将列表[self] 传递给Deck.__init__()。但是,我不能只将{self} 传递给Deck.__init__(),因为Card.__hash__() 可能需要已经设置了Deck 属性!有很多解决方法;我可以简单地在Card.__init__() 中设置self.owner = owner,或者我可以将[self] 传递给Deck.__init__(),然后在正文中设置self.cards = set(cards),但在我看来,代码的其他部分应该取决于甲板选择存储它的卡片。因此,我的问题不是如何编码,而是设计这种关系的最佳方式,这样我就不必担心这些问题。有什么想法吗?

我搜索了这个问题并没有找到任何东西,但这很简单,所以如果它是重复的,我很抱歉。感谢阅读!

编辑:如果一副纸牌对我的结构来说是一个不好的类比,一个(希望)更准确的类比是一个多项式,它是单项式的总和,但每个单项式也是一个多项式,它本身就是一个术语.

【问题讨论】:

  • 这对我来说毫无意义。当它显然是组合时,为什么要在继承中使用鞋拔呢?更好的设计方法是不使用继承。我的意思是,由一组卡片组成的套牌就像许多教程中使用的 OOP 的典型示例。
  • 我选择了一副牌来使我的例子尽可能简单,但也许那是个错误。这里的关键问题是关于具有上述属性的结构,而不是表示一副纸牌的最佳方式!
  • 你的结构本质上是没有意义的。您将事物容器与单个事物混淆。即使是这种情况,将 Card 类与在一起也没有任何意义。 为什么在这里使用继承?它完成什么?它从根本上不符合继承模型。即使在您的多项式示例中,为什么要使用继承?您的多项式类将简单地跟踪它的度数,因此单项式不会是子类,它只会具有度数 1。内置函数中的一个示例是 str 对象,其中包含其他 str 对象。

标签: python inheritance hash subclass self-reference


【解决方案1】:

我认为这里的问题是你的想法“一张牌可以被认为是一副牌。”不太连贯,您偶然发现了一个非常具体的说明。

一副牌与单张牌是一个根本不同的概念,为了使一副牌存在,非副牌也必须独立存在。

您可以通过考虑“添加一张牌”的操作来了解这一点——您应该能够在牌组中执行此操作,结果应该是一副牌中有两张牌。但是你不应该对一张牌这样做,因为那样其他一些已经包含这张牌的牌组会突然变成混合类型——它会有一些是一张牌,一些是两张牌,这不是卡片组的工作方式(并且会破坏迭代等)。

所以我认为这里的正确选择是在需要时简单地支持将牌组分成更小的牌组 — 可以将一张牌从牌组中移出建模为“将牌组分成两副牌,其中一张是 N-1 张牌和 1 张牌中的一张”,但 1 张牌组仍然需要在其中包含一个非牌组 Card 对象,否则您会遇到问题。

【讨论】:

  • 谢谢,您的回答让我意识到为什么这是一个坏主意。虽然我计划保持我的对象不可变,这否定了“添加一张卡”的困境,但我提出的结构仍然会在将 0 张卡添加到 1 张卡组或从 n 中删除 n-1 张卡时引起问题卡组。在决定输出什么类型时,总是检查是否只有一张卡会很笨重。
【解决方案2】:

我将忽略此设计的可疑之处,并专注于提供的代码中的错误。

AttributeError 是由{self} 引起的:

super().__init__({self}, owner)

这会尝试在完全初始化之前获取self 的哈希值。

{self} 替换为[self],您的代码就可以正常运行了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多