I made the following two functions:
def make_great(magicians):
for i in range(len(magicians)):
magicians[i] = " the Great."
def show_magicians(magicians):
for magician in magicians:
print(magician)
I then pass the copy of a list of magicians to the make_great function, assign it to the copy variable, and pass that to the show_magicians function:
magicians = ['Peter', 'Hendrick', 'Charles', 'Ryan', 'Alex']
copy = make_great(magicians[:])
show_magicians(copy)
Which gives me TypeError: 'NoneType' object is not iterable.
When I pass it the original list it works. However, I tried the following as well:
magicians = ['Peter', 'Hendrick', 'Charles', 'Ryan', 'Alex']
print(make_great(magicians))
make_great(magicians)
show_magicians(magicians)
Which gives the desired result, but the print function also returns a None object. I have two questions: 1) Why do I get the TypeError only with the list copy, and 2) Why does the make_great function return a None object in both cases (with the copy and the original list)?
CodePudding user response:
Your make_great()
function returns None
because it has no return
statement.
It uselessly updates its local copy of magicians
, which is then lost as it goes out of scope when the function ends. You need to return the magicians
list.
CodePudding user response:
make_great(magicians) needed a return from the function.
"When I pass it the original list it works." This was because magicians is mutable. make_great(magicians) changed each of the elements in the list.
def make_great(magicians):
for i in range(len(magicians)):
magicians[i] = " the Great."
return magicians
def show_magicians(magicians):
for magician in magicians:
print(magician)
magicians = ['Peter', 'Hendrick', 'Charles', 'Ryan', 'Alex']
copy = magicians[:]
print(f'{copy=}') # Verify copy is not equal to None
show_magicians(make_great(copy))
print(f'{copy=}') # Demonstrate make_great mutated the list copy
Output
copy=['Peter', 'Hendrick', 'Charles', 'Ryan', 'Alex']
Peter the Great.
Hendrick the Great.
Charles the Great.
Ryan the Great.
Alex the Great.
copy=['Peter the Great.', 'Hendrick the Great.', 'Charles the Great.', 'Ryan the Great.', 'Alex the Great.']
CodePudding user response:
If make_great
changes its argument in place, it's the caller's responsibility to maintain a reference to that list, not make_great
's responsibility to return a reference to it.
magicians = ['Peter', 'Hendrick', 'Charles', 'Ryan', 'Alex']
copy = magicians[:]
make_great(copy)
show_magicians(magicians)
If make_great
will make a copy, it should leave the original list unchanged and return a reference to the modified copy.
def make_great(magicians):
return [x "the Great." for x in magicians]
copy = make_great(magicians)
show_magicians(copy)