Search code examples
pythondictionaryexceptioniterationinfinite-loop

Iterating through python dictionary giving unexpected behavior


I need to iterate through a dictionary, assigning key values from user input based on a list. If the user enters anything other than valid values from the list, an else statement or exception catches it, and re-sets the list. I then need to take the values and pass them to a class object as parameters, like:

Class Player(self, strength, dexterity, constitution, intelligence, wisdom, charisma)
    self.strength = strength
    ...

I am expecting the variables to be set by the values, but all are still zero at the end of the function.

def character_generator():
    cls()
    player_name = input(f"Please enter character name: ")
    strength = 0
    dexterity = 0
    constitution = 0
    intelligence = 0
    wisdom = 0
    charisma = 0
    display_dict = {'Strength': strength,
                    'Dexterity': dexterity,
                    'Constitution': constitution,
                    'Intelligence': intelligence,
                    'Wisdom': wisdom,
                    'Charisma': charisma}
    score_list = [15, 14, 13, 12, 10, 8]
    
    while len(score_list):
        for key in display_dict.keys():
            cls()
            
            print(score_list)
            try:
                score = int(input(f"Enter score to assign to {key}: "))
                if score in score_list:
                    print(f"{key} = {score}")
                    display_dict[key] = score
                    score_list.remove(score)
                    
                else:
                    score_list = [15, 14, 13, 12, 10, 8]  # re-set list
                    print(f"Valid scores are listed above.")
                    sleep(.5)
                    print(f"Starting over.")
                    sleep(.5)
                    break
            except ValueError:
                print(f"Invalid entry..")
                score_list = [15, 14, 13, 12, 10, 8]  # re-set list
                sleep(.5)
                print(f"Starting over.")
                sleep(.5)
                break
    for key, value in display_dict.items():
        print(key, ':', value)
    print(strength)
    print(dexterity)
    print(constitution)
    print(intelligence)
    print(wisdom)
    print(charisma)


Solution

  • There is nothing that would update those local variables, so little wonder they're not getting updated.

    However, you also don't need them for anything – just use the dict as your single source of truth, and you can even ** splat it into your Character constructor.

    def character_generator():
        cls()
        player_name = input(f"Please enter character name: ")
        stats = {
            "strength": 0,
            "dexterity": 0,
            "constitution": 0,
            "intelligence": 0,
            "wisdom": 0,
            "charisma": 0,
        }
        score_list = [15, 14, 13, 12, 10, 8]
    
        while len(score_list):
            for key in stats:
                human_key = key.capitalize()
                cls()
    
                print(score_list)
                try:
                    score = int(input(f"Enter score to assign to {human_key}: "))
                    if score in score_list:
                        print(f"{key} = {score}")
                        stats[key] = score
                        score_list.remove(score)
    
                    else:
                        score_list = [15, 14, 13, 12, 10, 8]  # re-set list
                        print(f"Valid scores are listed above.")
                        sleep(0.5)
                        print(f"Starting over.")
                        sleep(0.5)
                        break
                except ValueError:
                    print(f"Invalid entry..")
                    score_list = [15, 14, 13, 12, 10, 8]  # re-set list
                    sleep(0.5)
                    print(f"Starting over.")
                    sleep(0.5)
                    break
        for key, value in stats.items():
            print(key, ":", value)
        player = Player(**stats)
    

    Further, I'd simplify your code to

    def character_generator():
        stats = {
            'strength': 0,
            'dexterity': 0,
            'constitution': 0,
            'intelligence': 0,
            'wisdom': 0,
            'charisma': 0,
        }
        score_list = [15, 14, 13, 12, 10, 8]
        assert len(score_list) == len(stats)  # So we haven't been silly
    
        for key in stats:
            human_key = key.capitalize()
            while True:
                try:
                    score = int(input(f"Enter score to assign to {human_key} (from {score_list}): "))
                except ValueError:
                    print("Please enter a valid number.")
                    continue
                if score in score_list:
                    print(f"{key} = {score}")
                    stats[key] = score
                    score_list.remove(score)
                    break
                else:
                    print(f"Invalid score. Please try again.")
        
        for key, value in stats.items():
            print(key, ':', value)
        player = Player(**stats)
    

    You could refactor that to multiple functions too – a smaller function to prompt for a valid input comes to mind.