Home > Blockchain >  Unexpected None when changing values of a list copy via function
Unexpected None when changing values of a list copy via function

Time:02-28

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)
  • Related