This is by design. A function accesses variables in its most general lexical scope (in this case, the top-level module) and can modify them at will. There is no copy being made. Even this is the reason why you should not use mutable data as parameters default function:
>>> def foo(x=[]):
... x.append('bar')
... print x
...
>>> foo()
['bar']
>>> foo()
['bar', 'bar']
>>> foo()
['bar', 'bar', 'bar']
If you need that within your function f
there is a list identical to that defined outside at the time of the call, which you can modify at will without interfering with the original list, the only output is to make a copy even. And your way of copying a list is ok.
P.S. Rereading your question, I realize that this is independent of the function access a variable from outside or not:
x = [1, 2]
def f(y):
y[1] = "novo valor"
return y
f(x)
def g():
x[1] = "novo valor"
return x
g()
Since the parameter is mutable, the changes made in it will persist after the end of the function.
Updating: if you are looking for a generic way of copying arguments from functions to prevent them from being accidentally changed, one way is to create a decorator that makes a deep copy of all its arguments:
>>> from copy import deepcopy
>>> def sem_efeitos_colaterais(f):
... def ret(*args, **kwargs):
... args = [deepcopy(x) for x in args]
... kwargs = { deepcopy(k):deepcopy(v) for k,v in kwargs.items() }
... return f(*args, **kwargs)
... return ret
...
>>> @sem_efeitos_colaterais
... def foo(x):
... x.append(3)
... return x
...
>>> x = [1,2]
>>> foo(x)
[1, 2, 3]
>>> x
[1, 2]
Note that this only ensures against changes in parameters, not against cases where the function accesses variables in its most general lexical scope (e.g.: the function g
from the previous example). And, of course, it is good to stress that make copies of all has a negative impact on performance...
I’m having a little trouble understanding the root of your doubt. Is it because, in Python, objects are passed by reference? (i.e. it is the same object) While in C it can also be passed).
– mgibsonbr
This, sometimes I want to make sure that the function will not have side effects, and I wanted to know the ways to do this in Python.
– Carlos Cinelli
Just like most object-oriented imperative languages, there are not many resources to do this in Python, it ends up being the responsibility of the same programmer... That question on the Soen seems to corroborate that statement. You can even create a decorator who makes a deep copy of all the arguments of a function, but this does not guarantee against all cases (in particular cases like the function
g
of my answer).– mgibsonbr