I'm writing a code for the card game 'War'. While defining a "Deck" class, I've defined an attribute "self.cards" which gives the list of all the cards currently in a deck of cards. I've also defined an attribute "self.length" which is expected to give the length of the "self.cards" attribute.
BUT, when I use the expression deck.length
, it returns a fixed value, which doesn't change even when the cards in the deck ("self.cards") are removed/added. On the other hand when I use the expression len(deck.cards)
, it returns the desired output (that is the updated size of the deck).
The code is:
# I've used only two suits and three ranks to explain this problem
suits = ('Hearts','Spades')
ranks = ('Queen','King','Ace')
class Card():
def __init__(self,suit,rank):
self.suit = suit
self.rank = rank
class Deck():
def __init__(self):
# Create an empty deck and fill it with the available cards
self.cards = []
for suit in suits:
for rank in ranks:
self.cards.append(Card(suit,rank))
self.length = len(self.cards)
def deal_top_card (self):
self.cards.pop(0)
deck = Deck()
# Removing Three cards one after the other
deck.deal_top_card()
deck.deal_top_card()
deck.deal_top_card()
print(f"Length according to length attribute = {deck.length}")
print(f"Length of the list of cards = {len(deck.cards)}")
The output of the code above is:
Length according to length attribute = 6
Length of the list of cards = 3
Your problem is that length
is a mere attribute. That means that it receives a value when it is defined, and keeps that value until it is assigned again.
But Python has a concept that does what you want with properties:
class Deck():
def __init__(self):
# Create an empty deck and fill it with the available cards
self.cards = []
for suit in suits:
for rank in ranks:
self.cards.append(Card(suit,rank))
@property
def length(self):
return len(self.cards)
def deal_top_card (self):
self.cards.pop(0)
A property is used as a special member that actually executes a method each time it is used. You can now successfully use:
deck = Deck()
# Removing Three cards one after the other
deck.deal_top_card()
deck.deal_top_card()
deck.deal_top_card()
print(f"Length according to length attribute = {deck.length}")
print(f"Length of the list of cards = {len(deck.cards)}")
and get as expected:
Length according to length attribute = 3
Length of the list of cards = 3
BTW, properties are even more powerful that that and can call other methods when assigned to or deleted. Read https://docs.python.org/3/library/functions.html#property for more...