propias - parametros por omision python
¿Buenos usos para los valores predeterminados del argumento de la función mutable? (6)
Es un error común establecer un objeto mutable como el valor predeterminado de un argumento en una función. Aquí hay un ejemplo tomado de este excelente artículo escrito por David Goodger :
>>> def bad_append(new_item, a_list=[]):
a_list.append(new_item)
return a_list
>>> print bad_append(''one'')
[''one'']
>>> print bad_append(''two'')
[''one'', ''two'']
La explicación de por qué sucede esto está here .
Y ahora, para mi pregunta: ¿hay un buen caso de uso para esta sintaxis?
Quiero decir, si todos los que se encuentran cometen el mismo error, lo depuran, lo comprenden y, a partir de ahí, intentan evitarlo, ¿de qué sirve esa sintaxis?
EDITAR (aclaración): el problema de argumento predeterminado mutable es un síntoma de una opción de diseño más profunda, es decir, que los valores de argumento predeterminados se almacenan como atributos en el objeto de función. Puede preguntar por qué se hizo esta elección; como siempre, tales preguntas son difíciles de responder adecuadamente. Pero ciertamente tiene buenos usos:
Optimizando para el rendimiento:
def foo(sin=math.sin): ...
Asir valores de objeto en un cierre en lugar de la variable.
callbacks = []
for i in range(10):
def callback(i=i): ...
callbacks.append(callback)
La respuesta canónica es esta página: http://effbot.org/zone/default-values.htm
También menciona 3 casos de uso "buenos" para el argumento predeterminado mutable:
- vinculante variable local al valor actual de la variable externa en una devolución de llamada
- caché / memoria
- Reenlace local de nombres globales (para código altamente optimizado)
Puede usarlo para almacenar valores en caché entre llamadas a funciones:
def get_from_cache(name, cache={}):
if name in cache: return cache[name]
cache[name] = result = expensive_calculation()
return result
pero generalmente ese tipo de cosas se hace mejor con una clase, ya que puede tener atributos adicionales para borrar el caché, etc.
Quizás no mutes el argumento mutable, pero sí esperas un argumento mutable:
def foo(x, y, config={}):
my_config = {''debug'': True, ''verbose'': False}
my_config.update(config)
return bar(x, my_config) + baz(y, my_config)
(Sí, sé que puede usar config=()
en este caso particular, pero me parece menos claro y menos general).
Si por algún motivo desea, mantenga siempre la lista vacía si no se proporciona ningún parámetro:
def bad_append(new_item, a_list=[]):
bad_append.__defaults__ = ([],)
a_list.append(new_item)
return a_list
import random
def ten_random_numbers(rng=random):
return [rng.random() for i in xrange(10)]
Utiliza el módulo random
, efectivamente un singleton mutable, como su generador de números aleatorios predeterminado.