Make changes to lists local to Python?

5

In Python how do I do to the function below change the list locally, that is, only in the scope of the function f without changing x set outside of f ?

x = [1, 2]
def f(x):
    x[1] = "novo valor"
    return x
f(x)

'''
f alterou o valor de x
'''

print x
[1, 'novo valor'] 

One solution I found was this:

def f(x):
    x = x[:]
    x[1] = "novo valor"
    return x

But that seemed a bit forced. Is there any other way?

    
asked by anonymous 25.09.2014 / 05:13

2 answers

2

This is by design. A function accesses variables in its more general lexical scope (in this case, the module's top-level ) and can modify them at will. There is no copy being made. Even this is why you should not use changeable data as default parameters of functions:

>>> def foo(x=[]):
...   x.append('bar')
...   print x
...
>>> foo()
['bar']
>>> foo()
['bar', 'bar']
>>> foo()
['bar', 'bar', 'bar']

If you need within your f function to have a list identical to the one defined at the time of the call, which you can modify at will without interfering with the original list, the only way out is to make a copy yourself. And your way of copying a list is ok.

P.S. By reading your question, I realize that this is independent of the function accessing 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 changeable, changes made thereto will persist after the function has terminated.

Update: If you are looking for a generic way of copying function arguments to prevent them from being accidentally changed, one way is to create a decorator that deepcopy of all your 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 guarantees against changes in parameters, not against cases where the function accesses variables in its more general lexical scope (eg, the g function in the previous example). And, of course, it's good to point out that making copies of everything has a negative impact on performance ...

    
25.09.2014 / 05:21
1

To make local changes to a list passed in an argument, you need to work on a copy of it.

x_local = list(x)
x_local[1] = 'Novo valor'
    
25.09.2014 / 09:54