Python function is changing the value of my input, and I can't figure out why

13,047

Solution 1

Inside your function, z and spins refer to the same list, which is also known by the global name of spin. If you modify one, those changes are visible through the other names as well. The variable z is superfluous.

If you want z to be a copy of spins then just do:

z = spins[:]

or:

z = list(spins)

Solution 2

The thing you are forgetting is that z and spins are essentially the same object. Both point to the same list and have the same elements.

For example:

a = [0]
b = a

b[0] = 1
print a

Result:

[1]

To copy the list instead, try something like this:

a = [0]
b = a[:]

b[0] = 1
print a

Result:

[0]

Solution 3

In Python, all objects are referenced by pointers. All variable names like spin and test are just pointers. When you assign spin to z you are just making z point to the same object as spin and then mutating the object pointed to by z (which is the same as the object pointed to by spin).

All function calls in Python are pass-by-value where the values are direct references to objects. Thus, if you mutate a list object within a function, it will appear mutated even after you return from the function.

You have to create a new copy of the list if you don't want to accidentally mutate spin. Other answers have shown ways of copying a list. I personally like the [:] syntax that kindall showed in his answer.

Share:
13,047

Related videos on Youtube

aetb
Author by

aetb

Physicist

Updated on June 14, 2022

Comments

  • aetb
    aetb almost 2 years

    This is my first question, so if I'm being a total dweeb posting this, let me know why and how I can avoid it in the future!

    I have a bit of python code that should just take a list, and multiply the jth component by -1. This is the code in question.

    def flip(spins,j):
        z = spins
        z[j] = z[j]*-1
        return z
    

    However, what I am noticing is that if I try to do something like

    spin = [1,1,1]
    test = flip(spin,1)
    

    it will assign the proper value [1,-1,1] to 'test', but it will also change the value of 'spin' to [1,-1,1]. I know there must be something totally obvious I'm overlooking, but I've been staring at this for 2 hours and still can't see it.

    Thanks for your help!

    • roippi
      roippi over 10 years
      Lists are mutable. You're passing a reference to that list to flip, making a second reference to that list, then mutating the list.
  • aetb
    aetb over 10 years
    Thanks, I had no idea that's how it worked. I thought variables all pointed to unique locations.
  • aetb
    aetb over 10 years
    I just tried this code a=4 b = a a = 5 print b and it would seem I should get 5, but it actually printed 4. What's the difference here?
  • Shashank
    Shashank over 10 years
    @aetb The difference is that integers in Python are not mutable. Therefore when you do 'a=5' you are not changing the value of the object pointed to by a. You are actually creating a new integer value '5' and making 'a' point to that.
  • Shashank
    Shashank over 10 years
    @aetb Lists, on the other hand, are mutable objects. So when you do something like z[j] = z[j]*-1 you are actually just mutating (changing the state of) the list object.
  • embulldogs99
    embulldogs99 over 2 years
    So when a function receives an input, it does not put it in a black box of its own. It will actually change the input if that input is edited and used inside the function?
  • kindall
    kindall over 2 years
    right. a function argument refers to same object that was passed in. if you don't change what object the argument refers to (using = specifically) then it's still the same object as was passed in, and any changes you make can be seen by the caller
  • Ver Nick
    Ver Nick over 2 years
    Hmm, does not work for me. Whatever method I use, the function still alters the original object.

Related