Error with recursion from call "random.shuffle()"

Question:

Im trying to create a very simple blackjack game, and I think I’m almost done, but when I try to play the game I get an error:

Traceback (most recent call last):
  File "c:Usersnils.edstromgithub-classroomNTI-Gymnasiet-Nackafebruariprojektet-Nilleni2Main.py", line 176, in <module>
    dealer = Dealer(player1)
  File "c:Usersnils.edstromgithub-classroomNTI-Gymnasiet-Nackafebruariprojektet-Nilleni2Main.py", line 107, in __init__
    self._dealer = Dealer('Dealer')
  File "c:Usersnils.edstromgithub-classroomNTI-Gymnasiet-Nackafebruariprojektet-Nilleni2Main.py", line 107, in __init__
    self._dealer = Dealer('Dealer')
  File "c:Usersnils.edstromgithub-classroomNTI-Gymnasiet-Nackafebruariprojektet-Nilleni2Main.py", line 107, in __init__
    self._dealer = Dealer('Dealer')
  [Previous line repeated 493 more times]
  File "c:Usersnils.edstromgithub-classroomNTI-Gymnasiet-Nackafebruariprojektet-Nilleni2Main.py", line 105, in __init__
    self._deck = Deck()
  File "c:Usersnils.edstromgithub-classroomNTI-Gymnasiet-Nackafebruariprojektet-Nilleni2Main.py", line 43, in __init__
    self.populate()
  File "c:Usersnils.edstromgithub-classroomNTI-Gymnasiet-Nackafebruariprojektet-Nilleni2Main.py", line 60, in populate
    random.shuffle(self._cards)
  File "C:Usersnils.edstromAppDataLocalProgramsPythonPython39librandom.py", line 360, in shuffle
    for i in reversed(range(1, len(x))):
RecursionError: maximum recursion depth exceeded while calling a Python object

This is my code:

import random

class Card:
    def __init__(self, suit, number):
        self._suit = suit
        self._number = number

    def __repr__(self):
        return self._number + ' of ' + self._suit

    #Allows the user to write my_card.suit
    @property
    def suit(self):
        return self._suit
    
    #Prevents the user from changing the suit of a card to unvalid values
    @suit.setter
    def suit(self, suit):
        if suit in ['Hearts', 'Clubs', 'Diamonds', 'Spade']:
            self._suit = suit
        
        else: 
            print("That's not a valid suit")

    #Allows the user to write my_card.number
    @property
    def number(self):
        return self._number
    
    #Prevents the user from chaninging the number of a card to something non-existent
    @number.setter
    def number(self, number):
        if number in ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']:
            self._number = number
        
        else:
            print("That's not a valid number")
        

class Deck:
    def __init__(self):
        self._cards = []
        self.populate()
    
    def __repr__(self) -> str:
        return f'{self._cards}'

    def populate(self):
        suits = ['Hearts', 'Clubs', 'Diamonds', 'Spades']
        numbers = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']

        cards = []
        for suit in suits:
            for number in numbers:
                cards.append(Card(suit, number))    
        
        self._cards = cards

        #Shuffles the deck so it's random what card is drawn each time
        random.shuffle(self._cards)

#Test
my_deck = Deck()
print(my_deck)

#Player class
class Player:
    def __init__(self, name, hand=None, score=0):
        self._name = name
        self._hand = [] if hand is None else hand
        self._score = score
    
    #Adds a card to the player hand
    def add_card(self, card):
        self._hand.append(card)
    
    def get_score(self):
        score = 0
        aces = 0
        for card in self._hand:
            if card.number == 'A':
                aces += 1
                score += 11
            
            elif card.number in ['J', 'Q', 'K']:
                score += 10
            
            else:
                score += int(card.number)
        
        #Calculates weather or not to count Aces as 1 or eleven depending on your score
        while aces > 0 and score > 21:
            value -= 10
            aces -= 1
        
        return score
            



# Dealer class
class Dealer:
    def __init__(self, player_name):
        self._hand = []
        self._deck = Deck()
        self._player = Player(player_name)
        self._dealer = Dealer('Dealer')

    
    def first_cards(self):
        self._player.add_card(self._deck._cards.pop())
        self._dealer.add_card(self._deck._cards.pop())
        self._player.add_card(self._deck._cards.pop())
        self._dealer.add_card(self._deck._cards.pop())

    def player_turn(self):
        while self._player.get_score() < 21:
            if str(input('Do you want to hit? (Y/N)')).lower() == 'y':
                self._player.add_card(self._deck._cards.pop())
                print(f'Your current hand is : {self._player.get_score()}')
            
            else:
                break

    def dealer_turn(self):
        while self._dealer.get_score() < 17:
            self._dealer.add_card(self._deck._cards.pop())
        print(f'The dealer's hand is: {self._dealer.get_score()}')


    def add_card(self, card):
        self._hand.append(card)

    def get_score(self):
        score = 0
        aces = 0
        for card in self._hand:
            if card.number == 'A':
                aces += 1
                score += 11
            
            elif card.number in ['J', 'Q', 'K']:
                score += 10
            
            else:
                score += int(card.number)
        
        #Calculates weather or not to count Aces as 1 or eleven depending on your score
        while aces > 0 and score > 21:
            score -= 10
            aces -= 1
        
        return score

    def start(self):
        print('Welcome to blackjack! By Nils Edstrom')
        self.first_cards()
        print(f'Your current hand is: {self._player.get_score()}')
        print(f'The dealer's current hand is: {self._dealer.get_score()}')

        self.player_turn()
        if self._player.get_score() > 21:
            print(f'You lose your current score is: {self._player.get_score()}')

        if self._player.get_score() > self._dealer.get_score():
            print('You won')

        elif self._player.get_score() < self._dealer.get_score():
            print('The dealer won')

        else:
            print('It's a tie')


player1 = str(input('What is your name? '))
dealer = Dealer(player1)
dealer.start()

I’m very frustarated with this, it seems to be coming from the populate method in the deck class specifically the random.shuffle() call. But I cannot figure out why it’s creating a recursion error.

I’m very frustarated with this, it seems to be coming from the populate method in the deck class specifically the random.shuffle() call. But I cannot figure out why it’s creating a recursion error.

Asked By: Nils Edström

||

Answers:

# Dealer class
class Dealer:
    def __init__(self, player_name):
        # ...
        self._dealer = Dealer('Dealer')

The constructor for Dealer is calling itself, this originates the recursion.

Answered By: Jonathan Ciapetti