1

I'm trying to pass a copy of a list to a function in python so I can pop and append to a new list without losing the information in the old list. But I'm having trouble.

here's my code

def show_magicians(magicians):
    for magician in magicians:
        print (magician.title())
        return magicians

def make_great(magicians):
    for magician in magicians:
        new_magician = magicians.pop()
        new_magicians.append(new_magician)
        print (new_magician.title() + ", is a great magician!!")
        return magicians

new_magicians = []
magicians = ['merlin', 'blaine', 'agaybi', 'copperfield']   
show_magicians(magicians)
make_great(magicians[:])
print ('\n' , magicians)
print ('\n' , new_magicians)

The second function is supposed to move the elements from the old list to the new and print the simple statement for each one without emptying the old list. The problem is I get only 1 element printed and the same element is the only element moved.

What am I doing wrong?

8
  • 1
    You don't assign the new list created by make_great, try new_magicians = make_great(magicians[:]). Commented Jun 22, 2016 at 15:29
  • 1
    @RobertR no, that's not the problem - the OP explicitly passes a shallow copy using the slice notation [:]. The problem is that that's unrelated to new_magicians! Commented Jun 22, 2016 at 15:29
  • Thank you for the edit Jon Sharpe. This is my first question. Commented Jun 22, 2016 at 15:30
  • @jonrsharpe He's doing new_magicians.append(...) though. Commented Jun 22, 2016 at 15:31
  • Yes the lesson is about using a shallow copy when calling the function so the pop() works on the copy rather than the original. How do I relate the shallow copy to `new_magicians' ? Commented Jun 22, 2016 at 15:33

3 Answers 3

2

You are returning after the first magician is processed

Change the make_great function as follows

def make_great(magicians):
    for magician in magicians:
        new_magician = magicians.pop()
        new_magicians.append(new_magician)
        print (new_magician.title() + ", is a great magician!!")
    return magicians
Sign up to request clarification or add additional context in comments.

3 Comments

Well it doesn't seem the return statement does anything because I hashtagged it and the same result happens. Now I get the old list intact but only the last two elements moved to the new list!!!!
The old list is intact because you send a copy of it to your function, and the other problem is probably because you modify a list while iterating on it. Your code is very confusing, why one list is passed as parameter and not the other ?
This doesn't work because it is popping items from the list being enumerated.
1

The existing answer solves your immediate problem, but your code is still unnecessarily confusing, which I think contributed to your getting stuck.

The "correct" way to do this is to avoid mutating magicians within make_great at all. A Python function taking a mutable argument like this should either mutate its argument and return None or create a new object and return that. It should certainly not (for such a trivial task at least) mutate both its argument and an object in the enclosing scope and return that second object.

For example, you could have done:

def make_great(magicians):
    """Make each magician in the input great."""
    new_magicians = []  # create a brand new list
    for name in magicians:  # iterate over old list
        new_magicians.append(name + ' is a great magician!')  # add to new list
    return new_magicians  # note this is outside the for loop

Then you don't need to create new_magicians outside the function, or pass a copy of the original magicians to it:

magicians = ['merlin', 'blaine', 'agaybi', 'copperfield']   
new_magicians = make_great(magicians)
print(magicians)  # still the same
print(new_magicians)  # brand new list

Comments

0

Ok so first of all thank you all so much. I finally figured out the problem and how to solve it. The exercise I'm working on specifically wants me to use the [:] to make a shallow copy of the list and pass it through a function to create a new list by popping.

The problem was I kept the for loop that prints the statement, inside the function instead of placing outside to be global.

Here's the new and correct code:

def show_magicians(magicians):
    for magician in magicians:
        print (magician.title())


def make_great(magicians):
    while magicians:
        new_magician = magicians.pop()
        new_magicians.append(new_magician)


new_magicians = []
magicians = ['merlin', 'blaine', 'agaybi', 'copperfield']
show_magicians(magicians)
make_great(magicians[:])

for magician in magicians:
    print ('\n' + magician.title() + " is a great magician!!")

print ('\n')
print (magicians)
print ('\n')
print (new_magicians)   

Thanks again and sorry for the confusion.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.