473,603 Members | 2,642 Online

# Constructor problem

I'm writing a simple class to represent a deck of cards. Here is the
stripped down version. Notice classes Deck and Deck2. Class Deck works,
Deck2 does not. My thinking is that it should be more efficient (a la
Deck2) to pre-create the list, and then modify it, rather than appending
Cards as in Deck.

# --------------------snip--------------
class Card:
def __init__(self, rank=0, suit=0):
self.rank=rank
self.suit=suit

def __repr__(self):
r = "A23456789T JQK"[self.rank]
s = "SHCD"[self.suit]
return r+s
class Deck:
def __init__(self):
self.deck = []
for r in range(13):
for s in range(4):
self.deck.appen d(Card(r,s))

class Deck2:
def __init__(self):
self.deck = 52 * [Card()]
n = 0
for r in range(13):
for s in range(4):
self.deck[n].rank = r
self.deck[n].suit = s
n = n + 1
a = Deck()
print "A --> ", a.deck
b = Deck2()
print "B --> ", b.deck
# ------------snap---------------------

Deck A looks right, 52 cards, one of each. Deck B, on the other hand, is
52 of the same card, all rank 12, suit 3.

What am I missing???

Thanks!
Nick.
Jul 18 '05 #1
5 1587
Nick wrote:
class Deck2:
def __init__(self):
self.deck = 52 * [Card()]

Here you are creating a single Card instance and putting the same object
into a list 52 times. Each slot in the list points to the same object.

Another lesson to take away from this: Don't optimize prematurely. The
simplest implementation should be fine unless proven otherwise via
profiling.

--
Robert Kern
rk***@ucsd.edu

"In the fields of hell where the grass grows high
Are the graves of dreams allowed to die."
-- Richard Harter
Jul 18 '05 #2
"Nick" <me************ *@hotmail.com> wrote in message
news:41******** **@alt.athenane ws.com...
I'm writing a simple class to represent a deck of cards. Here is the
stripped down version. Notice classes Deck and Deck2. Class Deck works,
Deck2 does not. My thinking is that it should be more efficient (a la
Deck2) to pre-create the list, and then modify it, rather than appending
I strongly suspect premature optimization here.
Cards as in Deck.

# --------------------snip--------------
class Card:
def __init__(self, rank=0, suit=0):
self.rank=rank
self.suit=suit

def __repr__(self):
r = "A23456789T JQK"[self.rank]
s = "SHCD"[self.suit]
return r+s
class Deck:
def __init__(self):
self.deck = []
for r in range(13):
for s in range(4):
self.deck.appen d(Card(r,s))

class Deck2:
def __init__(self):
self.deck = 52 * [Card()]
This creates a list of 52 references to the card created by Card().
n = 0
for r in range(13):
for s in range(4):
self.deck[n].rank = r
self.deck[n].suit = s
n = n + 1
a = Deck()
print "A --> ", a.deck
b = Deck2()
print "B --> ", b.deck
# ------------snap---------------------

Deck A looks right, 52 cards, one of each. Deck B, on the other hand, is
52 of the same card, all rank 12, suit 3.

What am I missing???

Thanks!
Nick.

class Deck3:
def __init__(self):
self.deck = [Card(r, s) for s in range(4) for s in range(13)]

Jul 18 '05 #3
Nick wrote:
I'm writing a simple class to represent a deck of cards. Here is the
stripped down version. Notice classes Deck and Deck2. Class Deck works,
Deck2 does not. My thinking is that it should be more efficient (a la
Deck2) to pre-create the list, and then modify it, rather than appending
Cards as in Deck.

# --------------------snip--------------
class Card:
def __init__(self, rank=0, suit=0):
self.rank=rank
self.suit=suit

def __repr__(self):
r = "A23456789T JQK"[self.rank]
s = "SHCD"[self.suit]
return r+s
class Deck:
def __init__(self):
self.deck = []
for r in range(13):
for s in range(4):
self.deck.appen d(Card(r,s))

class Deck2:
def __init__(self):
self.deck = 52 * [Card()]
n = 0
for r in range(13):
for s in range(4):
self.deck[n].rank = r
self.deck[n].suit = s
n = n + 1
a = Deck()
print "A --> ", a.deck
b = Deck2()
print "B --> ", b.deck
# ------------snap---------------------

Deck A looks right, 52 cards, one of each. Deck B, on the other hand, is
52 of the same card, all rank 12, suit 3.

What am I missing???

Thanks!
Nick.

self.deck = 52 * [Card()]

Problem is with this line. It doesn't do what you want.

Try this from interpreter prompt:

class card:
pass

deck=52*[card()]
id(deck[0])
id(deck[1])
....

You will notice that all 52 entries in the list point
to the same instance of the card class.

As far as performance is concerned you are doing what
is commonly called as premature optimization. I set
up a loop and complete deck creation takes only 0.00015
seconds (that's 0.15 milliseconds) on my machine. I
wouldn't worry about optimizing this part of the program.

-Larry
Jul 18 '05 #4
Nick <me************ *@hotmail.com> wrote:
...
I'm writing a simple class to represent a deck of cards. Here is the
stripped down version. Notice classes Deck and Deck2. Class Deck works,
Deck2 does not. My thinking is that it should be more efficient (a la
Deck2) to pre-create the list, and then modify it, rather than appending
Cards as in Deck.

Everybody's accusing you of premature optimization, and they have a
point, but, there IS a very simple approach that's fast and useful
(particularly in Python 2.4 -- if you're interested in performance, get
and use 2.4 beta 1 *NOW*!!!-): a list comprehension:

self.deck = [Card(r, s) for r in xrange(13) for s in xrange(4)]
Alex
Jul 18 '05 #5
Nick wrote:
I'm writing a simple class to represent a deck of cards. Here is the
stripped down version. Notice classes Deck and Deck2. Class Deck works,
Deck2 does not. My thinking is that it should be more efficient (a la
Deck2) to pre-create the list, and then modify it, rather than appending
Cards as in Deck.

Thanks for the replies... I smack my head in dismay.

Jul 18 '05 #6

This thread has been closed and replies have been disabled. Please start a new discussion.