Confused about modifying lists using two functions in Python
<p>I'm currently reading <em>Python Crash Course</em> by Eric Matthes and I'm having an incredibly difficult time understanding chapter 8 which is all about functions. I am stuck on exercise 8-10 which asks me to use a new function to change a list used in the previous exercise.</p>

<p>Here is the exercise:</p>

<pre><code>8-9. Magicians: Make a list of magician's names. Pass the list to a function called show_magicians(), which prints the name of each magician in the list.

8-10. Great Magicians: Start with a copy of your program from exercise 8-9. Write a function make_great() that modifies the list of magicians by adding the phrase the great to each magician's name. Call show_magicians() to see that the list has actually been modified.
</code></pre>

<p><strong>Here is my code for 8-9:</strong></p>

<pre><code>def show_magicians(names):
    """Print each magician name"""
    for name in names:
        msg = name.title()
        print(msg)

magician_names = ['sonic', 'tails', 'knuckles']
show_magicians(magician_names)
</code></pre>

<p>I've seen a very similar topic on this website and so I tried to use the code in the first answer on this page to help me out: <a href="http://stackoverflow.com/questions/39338405/python-crash-course-8-10">Python crash course 8-10</a></p>

<p>However, my code still appears to be incorrect as the compiler prints 'the great' 3 times after each name.</p>

<p><strong>Here is the current code I used for 8-10</strong></p>

<pre><code>def show_magicians(names):
    """Print each magician name"""
    for name in names:
        msg = name.title()
        print(msg)

magician_names = ['sonic', 'tails', 'knuckles']
show_magicians(magician_names)

def make_great(list_magicians):
    """Add 'Great' to each name."""
    for magician_name in magician_names:
        for i in range(len(list_magicians)):
            list_magicians[i] += " the great!"

make_great(magician_names)
show_magicians(magician_names)
</code></pre>

<p>I don't know why but it just seems that I've been struggling through out this entire chapter of functions. Does anyone by any chance have any recommended tutorials to take a look at to help me understand functions better? Thank you for your time.</p>

<p>As another answerer said, your nested loops are doing basically the same thing, but for each time the outer loop runs, the inner loop runs. Both loops are trying to iterate over the list of magicians, one using the name the list goes by outside the function (<code>magician_names</code>) and one using the name the list goes by inside the function (<code>list_magicians</code>). Either way would work, but both is too many. From this point of view, your misunderstanding is not of functions, but of loops.</p>

<p>But the fact that you mention <code>magician_names</code> inside the function at all shows a misconception. It will work, but it's bad form. Usually, the code of a function should refer exclusively to names that are passed to the function via the parameters. So in this case, you should discard the loop over <code>magician_names</code> and keep the loop over <code>list_magician</code>. There are exceptions to the rule, but you should have a definite reason in mind before breaking it. The justification for the rule is encapsulation: you can completely understand the function by reading its parameter list and its code, without having to ask about the role of anything outside the function.</p>

<p>If you accept the idea that functions should operate only on their parameters, then you have to ask, So how does a function affect the outside world? One answer is that the function <code>return</code>s something, and the outside world voluntarily does something with what was returned. Another answer is that the function's parameter happens to point to an object in the outside world, so that changing the object inside the function automatically changes it outside the function. I prefer the first way, but it's probably easier in your case to use the second. So when you pass <code>magician_names</code> into your function, Python renames it to <code>list_magicians</code>; you operate on <code>list_magicians</code> inside the function, so <code>magician_names</code> also changes outside the function; you return from the function, and the <em>name</em> <code>list_magicians</code> goes away, but the <em>changes</em> to <code>magician_names</code> survive.</p>

<p>Here's a last bit of advice, which extends your knowledge to "list comprehensions," a topic you probably haven't learned about yet (but they're perfect for this application): I recommend writing a function to operate on a single piece of data, then calling that function repeatedly, rather than trying to do both the repetition and the single-item data modification in the same function. Like this:</p>

<pre><code>def append_great(magician):
    return magician + " the Great"
</code></pre>

<p>With that function available, a list comprehension looks quite nice. It processes a list element by element, according to your instructions. Like this:</p>

<pre><code>&gt;&gt;&gt; magicians = [ "Houdini", "Fubini" ]
&gt;&gt;&gt; [ append_great(m) for m in magicians ]
['Houdini the Great', 'Fubini the Great']
</code></pre>

<p>Note that the list comprehension returned a new list; <code>magicians</code> remains unchanged, unless you change it yourself. Which is how things ought to be. Functions shouldn't reach out and touch the outside world (unless there's a really good reason); instead, the outside world should give some data to the function, receive the result, and use the result as the outside world knows best. That's my advocacy for the return-a-value way of affecting the outside world, but as I said, in this case it's easier to use the pass-a-reference way.</p>

python