Reputation: 132
I want to represent a structure that is something like an unordered deck of cards (in Python 3.7, say), which has the property that a single card can be thought of as a deck of size one.
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')
(The above returns AttributeError: 'Card' object has no attribute 'owner'
)
If I wanted my deck to be ordered, this would be simple, since the Card.__init__()
would just pass in the list [self]
to the Deck.__init__()
. However, I can't just pass in {self}
to Deck.__init__()
, since Card.__hash__()
may require Deck attributes to already be set! There are plenty of workarounds; I could simply set self.owner = owner
in Card.__init__()
, or I could pass [self]
to Deck.__init__()
and then set self.cards = set(cards)
in the body, but it seems weird to me that other parts of the code should depend on how the deck chooses to store its cards. Therefore, my question isn't how to code this, but rather the best way to design this kind of relationship so that I don't have to worry about these issues. Any ideas?
I searched for this question and didn't find anything, but it's pretty simple so I apologize if it's a duplicate. Thanks for reading!
Edit: If a deck of cards is a bad analogy for my structure, a (hopefully) more accurate analogy would be a polynomial, which is a sum of monomials, but each monomial is also a polynomial with just itself as a term.
Upvotes: 1
Views: 54
Reputation: 74655
I am going to ignore the questionably of this design and focus on the error in the supplied code.
The AttributeError
is caused by {self}
in:
super().__init__({self}, owner)
This attempts to take the hash of self
before it has been fully initialized.
Replace {self}
with [self]
and your code runs without issue.
Upvotes: 0
Reputation: 2323
I think the problem here is that your idea "a single card can be thought of as a deck of size one." is not quite coherent, and you've stumbled on a nicely concrete illustration of why.
A deck of one card is a fundamentally different concept from a single card, and in order for the deck-of-card to exist, a non-deck card must also independently exist.
You can see this by thinking about the operation "adding one card" — you should be able to do that to the deck, and it should result in a deck of two cards. But you should not be able to do that to a card, because then some other deck which already contains the card would suddenly be of mixed type — it would have some cards that are one card, and some that are two, which is not a way that decks of cards work (and would break iteration, etc).
So I think the correct choice here is to simply support breaking decks into smaller decks when you need to — it's fine to model moving a card out of the deck as "splitting the deck into two decks, one of N-1 cards and one of 1 card", but the 1-card deck still needs to have a non-deck Card object inside it, or you'll have problems.
Upvotes: 1