2012-03-02 11 views
46

Tengo una función de Python que toma una lista como parámetro. Si fijo el valor predeterminado del parámetro a una lista vacía como esto:¿La mejor práctica para establecer el valor predeterminado de un parámetro que se supone que es una lista en Python?

def func(items=[]): 
    print items 

Pylint me decía "valor por defecto peligroso [] como argumento". Entonces me preguntaba ¿cuál es la mejor práctica aquí?

+3

esto es algo que cada novato de pitón se corta el dedo del pie una o dos veces, ¡es genial que la pildora le haya impedido escribir un error horrible! – wim

Respuesta

64

Uso None como un valor por defecto:

def func(items=None): 
    if items is None: 
     items = [] 
    print items 

El problema con un argumento predeterminado mutable es que va a ser compartida entre todas las invocaciones de la función - ver el "importante advertencia" en el relevant section of the Python tutorial.

+2

Ah, guau, me sorprende que la gente lo sepa. =) Detestaba tanto esta característica de Python que escribí mi propia biblioteca de decorador para permitir la sintaxis 'func (items = new ([]))'. – ninjagecko

+0

¡Gracias! Parece que Python piensa que None es un tipo completamente diferente de la lista, así que me preguntaba si es aceptable en Python establecer el valor predeterminado de un parámetro en un tipo diferente (como None) (sé que Python es un tipo sin idioma, pero vengo de C++ ... jajaja)? –

+0

Es bastante diferente a un lenguaje fuertemente tipado como C++. Solo piense en variables como nombres que hacen referencia a objetos, y todo se pasa por referencia. – wim

2

Para objeto mutable como un parámetro predeterminado en declaraciones de funciones y métodos, el problema es que la evaluación y la creación tienen lugar exactamente en el mismo momento. El analizador de Python lee la función-head y la evalúa en el mismo momento.

La mayoría de los principiantes asumen que se crea un objeto nuevo en cada llamada, ¡pero eso no es correcto! Un objeto (en su ejemplo, una lista) se crea en el momento de la DECLARACIÓN y no a petición cuando llama al método.

Para objetos imputables que no es un problema, porque incluso si todas las llamadas comparten el mismo objeto, es imparable y, por lo tanto, sus propiedades siguen siendo las mismas.

Como una convención se utiliza el objeto None para los valores predeterminados para indicar el uso de una inicialización predeterminada, que ahora puede tener lugar en el cuerpo de la función, que naturalmente se evalúa en el tiempo de llamada.

0

Además, y también para comprender mejor lo que es Python, aquí mi pequeño fragmento temática:

from functools import wraps 
def defaultFactories(func): 
    'wraps function to use factories instead of values for defaults in call' 
    defaults = func.func_defaults 
    @wraps(func) 
    def wrapped(*args,**kwargs): 
     func.func_defaults = tuple(default() for default in defaults) 
     return func(*args,**kwargs) 
    return wrapped 

def f1(n,b = []): 
    b.append(n) 
    if n == 1: return b 
    else: return f1(n-1) + b 

@defaultFactories 
def f2(n,b = list): 
    b.append(n) 
    if n == 1: return b 
    else: return f2(n-1) + b 

>>> f1(6) 
[6, 5, 4, 3, 2, 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, 3, 2, 1] 
>>> f2(6) 
[1, 2, 3, 4, 5, 6] 
4

simplemente me encontré con esto por primera vez, y mi primer pensamiento es "bueno, yo no quiero para mutar la lista de todos modos, entonces lo que realmente quiero es establecer de forma predeterminada una lista inmutable, así que Python me dará un error si accidentalmente lo mudo ". Una lista inmutable es solo una tupla. Por lo tanto:

 
    def func(items=()): 
     print items 

Claro, si se le pasa a algo que realmente no quiere una lista (por ejemplo isinstance (artículos, lista)), entonces esto te meta en problemas. Pero eso es un olor de código de todos modos.

+1

Y si dentro de la función necesita hacer una copia, use 'my_copy = list (items)'. Se le ocurrió una solución simple y muy inteligente para un problema común. –

Cuestiones relacionadas