Pase la lista para funcionar por valor

Quiero pasar una lista en función por valor. Por defecto, las listas y otros objetos complejos pasados ​​a la función por referencia. Aquí hay alguna decisión:

def add_at_rank(ad, rank): result_ = copy.copy(ad) .. do something with result_ return result_ 

¿Se puede escribir esto más corto? En otras palabras, quiero no cambiar de anuncio .

Puede usar [:] , pero para la lista que contiene listas (u otros objetos mutables) debe ir a copy.deepcopy() :

lis[:] es equivalente a list(lis) o copy.copy(lis) , y devuelve una copia superficial de la lista.

 In [33]: def func(lis): print id(lis) ....: In [34]: lis = [1,2,3] In [35]: id(lis) Out[35]: 158354604 In [36]: func(lis[:]) 158065836 

Cuándo usar deepcopy() :

 In [41]: lis = [range(3), list('abc')] In [42]: id(lis) Out[42]: 158066124 In [44]: lis1=lis[:] In [45]: id(lis1) Out[45]: 158499244 # different than lis, but the inner lists are still same In [46]: [id(x) for x in lis1] = =[id(y) for y in lis] Out[46]: True In [47]: lis2 = copy.deepcopy(lis) In [48]: [id(x) for x in lis2] == [id(y) for y in lis] Out[48]: False 

Este podría ser un caso de uso interesante para una función de decorador. Algo como esto:

 def pass_by_value(f): def _f(*args, **kwargs): args_copied = copy.deepcopy(args) kwargs_copied = copy.deepcopy(kwargs) return f(*args_copied, **kwargs_copied) return _f 

pass_by_value toma una función f como entrada y crea una nueva función _f que _f profundidad todos sus parámetros y luego los pasa a la función original f .

Uso:

 @pass_by_value def add_at_rank(ad, rank): ad.append(4) rank[3] = "bar" print "inside function", ad, rank a, r = [1,2,3], {1: "foo"} add_at_rank(a, r) print "outside function", a, r 

Salida:

 "inside function [1, 2, 3, 4] {1: 'foo', 3: 'bar'}" "outside function [1, 2, 3] {1: 'foo'}" 

Una copia superficial generalmente es lo suficientemente buena y potencialmente es más rápida que una copia profunda.

Puede aprovechar esto si las modificaciones que está realizando en result_ no están mutando los elementos / atributos que contiene .

Para un ejemplo simple si tienes un tablero de ajedrez

 board = [[' ']*8 for x in range(8)] 

Podrías hacer una copia superficial.

 board2 = copy.copy(board) 

Es seguro agregar / insertar / board2 / eliminar / reemplazar elementos de board2 , pero no las listas que contiene. Si desea modificar una de las listas continuas, debe crear una nueva lista y replace la existente.

 row = list(board2[2]) row[3] = 'K' board2[2] = row 

Es un poco más de trabajo, pero mucho más eficiente en tiempo y almacenamiento.

En caso de que el anuncio esté en la lista , puede simplemente llamar a su función como add_at_rank(ad + [], rank) .

Esto creará NUEVA instancia de lista cada vez que llame a la función, ese valor equivalente al anuncio .

 >>>ad == ad + [] True >>>ad is ad +[] False 

Pythonic puro 🙂