Reputation: 13
While trying to come up with a Hand class for a card game I encountered a strange behavior from an attribute
if I try to set self.number
as seen below it wont show the proper output
but if I make the same argument through a function total()
it works properly
my question is: why does the attribute self.number
not getting the value of len(self.cards)
?
class Hand (object):
def __init__(self,number=0,cards=[]):
self.cards=cards
self.number=len(self.cards)
def total(self):
return len(self.cards)
hand=Hand()
hand.cards.append(9)
print hand.cards
print len(hand.cards)
print hand.number
print hand.total()
output:
[9]
1
0 #I want this to be equal to 1
1
Upvotes: 1
Views: 40
Reputation: 9010
The attribute self.number
is set at instantiation, use a property instead.
class Hand (object):
def __init__(self, cards=None):
self.cards = cards or []
@property
def number(self):
return len(self.cards)
def total(self):
return len(self.cards)
Upvotes: 4
Reputation: 10512
Setting an instance variable to an expression does not create a binding between the inputs of that expression and the value of the instance variable. In other terms, setting self.number
to len(self.cards)
does not mean that self.number
will get updated whenever you update self.cards
.
Your program is functioning properly: When you create your object, len(self.cards)
is 0, so self.number
gets set to 0. When you change hand.cards
, there are no statements changing self.number
, so it stays 0.
The proper way to make your self.number
attribute update is to use a getter-setter pair in order to make sure that self.number
changes whenever self.cards
changes.
The Pythonic way to create a getter-setter pair is to use the @property
decorator.
In your case, you could do it like this:
class Hand(object):
def __init__(self, number = 0, cards = None):
self.cards = cards or []
@property
def number(self):
return len(self.cards)
This way, even though it looks to anyone uses your class that they are reading an attribute, what actually happens under the hood is that the number()
method gets called and correctly computes the current length of self.cards
.
Upvotes: 2