[Tutor] Python Variables Changing in Other Functions

Andre Engels andreengels at gmail.com
Wed May 25 07:27:32 CEST 2011


On Wed, May 25, 2011 at 6:14 AM, Rachel-Mikel ArceJaeger
<arcejaeger at gmail.com> wrote:

> I am having trouble with determining when python is passing by reference and by value and how to fix it to do what I want:
>
> I am writing a program that will take in a list of book titles and will allow many people to rank them in terms of popularity and will export the results to Excel. I'll include the whole code below, but the function I'm having trouble with is rankRandom(). I want it to take in a list of titles, randomize the list (so that I can be certain the order isn't influencing the results of the rankings), get a person's rankings, and then resort the order of the rankings to match the original order of title list (that way I can match up different people's rankings to the correct title).
>
> The issue is this: random.shuffle() mutates the list in place, rather than creating a new copy. This is fine, but rather than modifying just the local copy of my titles, it is modifying it in the other functions, too. For instance, rankRandom() is called by main(), which passes it listOfTitles. When rankRandom() returns, listOfTitles has been changed to the randomized version of titles.
>
> To fix this, I tried copying the original title list and then assigning it to the mutated version right before the rankRandom() function returns. The local version of titles in rankRandom() does indeed regain its original value, but listOfTitles in main() is still being assigned to the randomized version, and not to the original version. This boggles me, since it seems like shuffle is mutating the titles as if it were a global variable, but assignment is treating it only as a local.
>
> What exactly is going on here, and how do I avoid this problem?

You should not think of 'pass by reference' or 'pass by value'. That's
how things work in the C world. In Python, the data model is that
variables are a name for an object. What you are providing when
calling an argument with a function is not the variable itself, be it
by reference or by value, but the object that the variable refers to.

Thus, in your code, when calling rank_random(), "title" becomes
(within the function) a name of the object that also has the name
listOfTitles in main(). This object is then changed by
random.shuffle(). The assignment

titles = origTitles

gives the object referred to by origTitles a new name, 'titles'. This
does _not_ change the object that originally had the name titles,
which thus still has the shuffled value.

As for how to do what you wanted to do, do make a copy like you do,
but then _do the shuffling on the copy_. You could also change the
call to the function to have a copy rather than the original variable
as its argument, but that solution is not as useful for re-use of the
function.

Oh, and one more remark: copying a list objects is often done using

objects[:]

rather than

copy.copy(objects)



-- 
André Engels, andreengels at gmail.com


More information about the Tutor mailing list