I'm trying to use a for
loop to iterate through a set of objects, check if those objects store string data (specifically their 'Pokemon.evolution' variable) which is the same as a the name of one of the objects in the set, and then replace that string with the object of the matching name.
I've tried various ways of writing the for
loop, but nothing seems to do what I want it to. Here it is in "plain speak" to hopefully explain what I mean:
for x in ():
if Pokemon.name is in pokemon_db:
pokemon_db = Pokemon.evolution
else:
pass
As recommended, I should show some of my attempted for
loops, which are here:
def evolution_needs_updating_1():
for Pokemon in pokemon_db:
if Pokemon.evolution in pokemon_db is type(str):
print("Pokemon evolution needs updating")
print("Correct evoltuion in place")
''' Error Message:
File "Pokedex_Project\pokedex_project.(v.0.1.2).py", line 102, in <module>
evolution_needs_updating_1()
~~~~~~~~~~~~~~~~~~~~~~~~~~^^
File "Pokedex_Project\pokedex_project.(v.0.1.2).py", line 98, in evolution_needs_updating_1
if Pokemon.evolution in pokemon_db is type(str):
^^^^^^^^^^^^^^^^^
AttributeError: 'str' object has no attribute 'evolution' '''
def evolution_needs_updating_2():
for Pokemon in pokemon_db:
if Pokemon_db.evolution is str:
print("Pokemon evolution needs updating")
''' Error Message:
File "Pokedex_Project\pokedex_project.(v.0.1.2).py", line 109, in <module>
evolution_needs_updating_2()
~~~~~~~~~~~~~~~~~~~~~~~~~~^^
File "Pokedex_Project\pokedex_project.(v.0.1.2).py", line 106, in evolution_needs_updating_2
if Pokemon_db.evolution is str:
^^^^^^^^^^
NameError: name 'Pokemon_db' is not defined. Did you mean: 'pokemon_db'? '''
for pokemon in pokemon_db:
if pokemon.evolution == str in pokemon_db:
print(Pokemon.HasEvolution)
''' Error Message:
pokedex_project.(v.0.1.2).py", line 112, in <module>
if pokemon.evolution == str in pokemon_db:
^^^^^^^^^^^^^^^^^
AttributeError: 'str' object has no attribute 'evolution' '''
The for
loop I'm trying to make is to automate something I can do manually, and here is the code for doing it manually:
print(type(ivysaur.evolution)) # Output: <class 'str'> - Shows it's still the orignal string I inputted
print(ivysaur.evolution) # Output: venusaur - The original string
# Evolution updates to object's attributes
ivysaur.evolution = venusaur # Changes the ivysaur .evolution object's attribute to the venusaur
charmeleon.evolution = charizard # Same idea for Charmeleon
wartortle.evolution = blastoise # And same again for Wartortle
print(ivysaur.pokedex_number) # Output: 0002
print(ivysaur.evolution.name) # Output: Venusaur - Now showing self.name for Venusaur, meaning the change worked
print(ivysaur.evolution.pokedex_number) # Output: 0003 - Showing Venusaur's self.pokedex_number, again, showing it changed correctly
print(f"Ivysaur's evolution is {ivysaur.evolution.name}, and it originally evolves from {ivysaur.pre_evolution.name}.") # Output: Ivysaur's evolution is Venusaur, and it originally evolves from Bulbasaur.
Just for clarification, here is the class & the dict storing all of the Pokemon Class variables together:
class Pokemon:
def __init__(self, name, pokedex_number, height, weight, category, abilities, type, weaknesses, pre_evolution, evolution, image):
self.name = name
self.pokedex_number = pokedex_number
self.height = height # in Metres (Format: float)
self.weight = weight # in Kilograms (Format: float)
self.category = category
self.abilities = abilities
self.type = type
self.weaknesses = weaknesses
self.pre_evolution = pre_evolution # If n/a - Mark as ' False '
self.evolution = evolution # If n/a - Mark as ' False '
self.image = image # Pokedex image stored in 'pokedex_images' folder
...
bulbasaur = Pokemon("Bulbasaur", "0001", 0.7, 6.9, "Seed", ["Overgrow"], ["Grass", "Poison"], ["Fire", "Ice", "Flying", "Psychic"], None, "ivysaur", ...)
ivysaur = Pokemon("Ivysaur", "0002", 1.0, 13.0, "Seed", ["Overgrow"], ["Grass", "Poison"], ["Fire", "Ice", "Flying", "Psychic"], bulbasaur, "venusaur", ...)
venusaur = Pokemon("Venusaur", "0003", 2.0, 100.0, "Seed", ["Overgrow"], ["Grass", "Poison"], ["Fire", "Ice", "Flying", "Psychic"], ivysaur, None, ...)
charmander = Pokemon("Charmander", "0004", 0.6, 8.5, "Lizard", ["Blaze"], ["Fire"], ["Water", "Ground", "Rock"], None, "charmeleon", ...)
charmeleon = Pokemon("Charmeleon", "0005", 1.1, 19.0, "Flame", ["Blaze"], ["Fire"], ["Water", "Ground", "Rock"], charmander, "charizard", ...)
charizard = Pokemon("Charizard", "0006", 1.7, 90.5, "Flame", ["Blaze"], ["Fire"], ["Water", "Ground", "Rock"], "charmeleon", None, ...)
squirtle = Pokemon("Squirtle", "0007", 0.5, 9.0, "Tiny Turtle", "Torrent", ["Water"], ["Grass", "Electric"], None, "wartortle", ...)
wartortle = Pokemon("Wartortle", "0008", 1.7, 90.5, "Turtle", "Torrent", ["Water"], ["Grass", "Electric"], squirtle, "blastoise", ...)
blastoise = Pokemon("Blastoise", "0009", 1.7, 90.5, "Shellfish", "Torrent", ["Water"], ["Grass", "Electric"], "wartortle", None, ...)
pokemon_db = {
"0001" : bulbasaur,
"0002" : ivysaur,
"0003" : venusaur,
"0004" : charmander,
"0005" : charmeleon,
"0006" : charizard,
"0007" : squirtle,
"0008" : wartortle,
"0009" : blastoise}
I've managed to figure out how to answer my own query. Having everyones input was incredibly helpful in teaching me about certain aspects of Python and how classes interact with dictionaries. All of your answers helped massively to guide me to my solution, so I am very grateful for the contributions from: "Neil Butcher", "Mark Tolonen" and "Marce Puente".
Here is how I managed to get the code to use the dictionary's values for each pokemon and also the data stored within the variables/instances of the class to find and then replace Pokemon's evolutions if they need updating.
Firstly, I needed to change the dictionary from having the keys for each variable as their pokedex number and just use their name as the key, to help the for
loop I use later on with its comparisons.
pokemon_database = {
"bulbasaur" : bulbasaur,
"ivysaur" : ivysaur,
"venusaur" : venusaur,
"charmander" : charmander,
"charmeleon" : charmeleon,
"charizard" : charizard,
"squirtle" : squirtle,
"wartortle" : wartortle,
"blastoise" : blastoise,
"caterpie" : caterpie,
"metapod" : metapod,
"butterfree" : butterfree,
"weedle" : weedle,
"kakuna" : kakuna,
"beedrill" : beedrill
}
Then, after much trial and error with different versions of the for
loop, I stumbled into creating this loop. As far as I can tell, it loops through the dictionary using the values of the stored items, rather than the keys, and compares these variables' stored "evolution" data if it is a string or not. If it is a string, then it replaces it with the corresponding variable name for the evolution it has found.
def update_evolutions(pokemon_database):
for pkmon in pokemon_database.values():
if pkmon.evolution:
pkmon.evolution = pokemon_database[pkmon.evolution]
updated_pokemon_list.append(pkmon.evolution.name)
update_evolutions(pokemon_database)
Although not part of the actual loop, the "updated_pokemon_list" line is to add the Pokemon that have been found that needed updating, and then adding them to a list so I could check which Pokemon it had found during its loop that needed updating, just to check what it's doing.
I then added some code before and after the loop to make sure it was doing what I intended it to do, and I'll include that in its entirety for transparency.
# Debugging test - See which Pokemon were updateds
updated_pokemon_list: list = []
print(f"Bulbasaur evolves into {bulbasaur.evolution}, then it evolves eventually into {ivysaur.evolution}.") # Wouldn't let me add a further ".name" after each evolution since it caused an error. Showing it was still stored as a string.
# Automatically update any Pokemon's evolutions to link to the correct variable
def update_evolutions(pokemon_database):
for pkmon in pokemon_database.values():
if pkmon.evolution:
pkmon.evolution = pokemon_database[pkmon.evolution]
updated_pokemon_list.append(pkmon.evolution.name)
update_evolutions(pokemon_database)
print(bulbasaur.evolution.name)
print(f"Bulbasaur evolves into {bulbasaur.evolution.name}, then it evolves eventually into {ivysaur.evolution.name}.")
print(updated_pokemon_list)
The output of this block was:
Bulbasaur evolves into ivysaur, then it evolves eventually into venusaur.
Ivysaur
Bulbasaur evolves into Ivysaur, then it evolves eventually into Venusaur.
['Ivysaur', 'Venusaur', 'Charmeleon', 'Charizard', 'Wartortle', 'Blastoise', 'Metapod', 'Butterfree', 'Kakuna', 'Beedrill']
Again, thank you for all your help.