0

I assumed that whenever you passed an object into a function, it automatically created a separate copy for you that you could modify without changing the original. However, the following code terminates with this error every time.

>>> testvar = ['a' for a in range(100000)]
>>> def func(arg):
        while arg is testvar:
            arg.pop()
>>> func(testvar)
Traceback (most recent call last):
  File "<pyshell#47>", line 1, in <module>
    thing(m)
  File "<pyshell#43>", line 3, in thing
    obj.pop()
IndexError: pop from empty list
2

2 Answers 2

2

"I assumed that whenever you passed an object into a function, it automatically created a separate copy for you that you could modify without changing the original."

Well, your assumption there is wrong. Variables are passed by reference, not value. This includes if you set a default value for an argument to an empty list, and change it in the function, the next time you try to use that default value, it won't be an empty list anymore.

def foo(bar=[]):
    bar.append("baz")

foo()
foo()
# bar is now ["baz", "baz"]
Sign up to request clarification or add additional context in comments.

8 Comments

"Most" variables? I'd say all.
@chepner Not integers and floats, at least.
@fishsticks: integers behave exactly the same way as lists-- no copies are made. It's simply that integers aren't mutable. Try the_num = 1; print(id(the_num)); def add(num): print(id(num)); add(the_num).
num += 1 has the same effect as num = num + 1 because ints are immutable; the original object reference by num is still the same object that is passed as the argument.
@DSM in that particular case, it's because 1 is special (small integers are cached). You are correct in general though.
|
2

from: https://docs.python.org/3.4/library/copy.html

Assignment statements in Python do not copy objects, they create bindings between a target and an object. For collections that are mutable or contain mutable items, a copy is sometimes needed so one can change one copy without changing the other. This module provides generic shallow and deep copy operations (explained below).

when you are calling your function, you are doing the following:

func(arg=testvar)

If you want to have an actual copy of your data you could modify your function to the following:

def func(arg):
    arg_copy = arg[:]
    # mutate arg_copy here without mutating arg

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.