2011-01-30 22 views
73

De alguna manera, en la clase Nodo a continuación, las variables wordList y adjacencyList se comparten entre todas las instancias de Node.Constructor Python y valor predeterminado

>>> class Node: 
...  def __init__(self, wordList = [], adjacencyList = []): 
...   self.wordList = wordList 
...   self.adjacencyList = adjacencyList 
... 
>>> a = Node() 
>>> b = Node() 
>>> a.wordList.append("hahaha") 
>>> b.wordList 
['hahaha'] 
>>> b.adjacencyList.append("hoho") 
>>> a.adjacencyList 
['hoho'] 

¿Hay alguna manera de que pueda seguir usando el valor por defecto (lista vacía en este caso) para los parámetros del constructor pero para llegar a y b para tener sus propias variables lista de palabras y adjacencyList?

Estoy usando python 3.1.2.

+1

posible duplicado de [Cómo debo declarar valores por defecto para las variables de instancia en Python?] (Http://stackoverflow.com/questions/2681243/how-should-i-declare-default-values-for- instance-variables-in-python) –

+0

Posible duplicado de ["Menos asombro" en Python: ¿cuál ámbito es el argumento predeterminado mutable en?] (http://stackoverflow.com/questions/1132941/least-astonishment-in-python -which-scope-is-the-mutable-default-argument-in) –

Respuesta

91

Los argumentos predeterminados de la mutación generalmente no hacen lo que usted desea. En su lugar, intente esto:

class Node: 
    def __init__(self, wordList=None, adjacencyList=None): 
     if wordList is None: 
      self.wordList = [] 
     else: 
      self.wordList = wordList 
     if adjacencyList is None: 
      self.adjacencyList = [] 
     else: 
      self.adjacencyList = adjacencyList 
+20

Estos también pueden ser de una línea: 'self.wordList = wordList si wordList no es None else []', o , ligeramente menos seguro, 'self.wordList = wordList o []'. –

+1

Esto se considera la forma Pythonic, pero prefiero la manera de krousey porque "los casos especiales no son lo suficientemente especiales". –

+0

@JoshBleecherSnyder No pude identificarlo, ¿qué hace que este último sea menos seguro que el anterior? – markdsievers

15

me gustaría probar:

self.wordList = list(wordList) 

para forzarlo a hacer una copia en lugar de hacer referencia al mismo objeto.

+1

+1 por simplicidad :) – Hery

23

Vamos a ilustrar lo que está sucediendo aquí:

Python 3.1.2 (r312:79147, Sep 27 2010, 09:45:41) 
[GCC 4.4.3] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> class Foo: 
...  def __init__(self, x=[]): 
...   x.append(1) 
... 
>>> Foo.__init__.__defaults__ 
([],) 
>>> f = Foo() 
>>> Foo.__init__.__defaults__ 
([1],) 
>>> f2 = Foo() 
>>> Foo.__init__.__defaults__ 
([1, 1],) 

se puede ver que los argumentos por defecto se almacenan en una tupla que es un atributo de la función en cuestión. Esto en realidad no tiene nada que ver con la clase en cuestión y va para cualquier función. En python 2, el atributo será func.func_defaults.

Como han señalado otros carteles, probablemente desee utilizar None como valor centinela y otorgar a cada instancia su propia lista.

11
class Node: 
    def __init__(self, wordList=None adjacencyList=None): 
     self.wordList = wordList or [] 
     self.adjacencyList = adjacencyList or [] 
Cuestiones relacionadas