2010-05-21 14 views
8

Codice in test.py:Le classi base Python condividono gli attributi?

class Base(object): 
    def __init__(self, l=[]): 
     self.l = l 

    def add(self, num): 
     self.l.append(num) 

    def remove(self, num): 
     self.l.remove(num) 

class Derived(Base): 
    def __init__(self, l=[]): 
     super(Derived, self).__init__(l) 

Python sessione di shell:

Python 2.6.5 (r265:79063, Apr 1 2010, 05:22:20) 
[GCC 4.4.3 20100316 (prerelease)] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import test 
>>> a = test.Derived() 
>>> b = test.Derived() 
>>> a.l 
[] 
>>> b.l 
[] 
>>> a.add(1) 
>>> a.l 
[1] 
>>> b.l 
[1] 
>>> c = test.Derived() 
>>> c.l 
[1] 

mi aspettavo "C++ - come" un comportamento, in cui ogni oggetto derivato contiene la propria istanza della classe base. È ancora così? Perché ogni oggetto sembra condividere la stessa istanza di lista?

+0

possibile duplicato [ "Least Stupore" in Python: Il Mutevole argomento di default] (http://stackoverflow.com/questions/1132941/least-astonishment-in-python- l'argomento-mutable-default) –

risposta

14

Stai commettendo un errore comune di nuovo arrivato in Python.

Vedere la mia risposta qui: How should I declare default values for instance variables in Python?

Brevemente ha spiegato, Python interpreta le definizioni di classe solo volta. Ciò significa che tutto quanto dichiarato nel metodo __init__() viene creato solo una volta. In altre parole, l'argomento predefinito dell'elenco [] viene creato una sola volta.

Quindi il self.l = l assegna un riferimento alla stessa istanza ogni volta che si crea una nuova classe, quindi il comportamento che non si aspettava.

Il modo Pythonic è questo (codice parziale):

def __init__(self, arg=None): 
    if arg is None: 
     arg = [] 
    self.arg = arg 

Inoltre, si dovrebbe considerare l'utilizzo di una migliore convenzione di denominazione di l, che è difficile da leggere e potrebbe essere scambiato come 1 o |.

+0

+1 per la risposta corretta, ma sarebbe bello scriverlo qui, almeno brevemente. – Etaoin

+1

Lo farò, allora. ':]' –

+0

Ovviamente, questo è uno snippet di test. Non sceglierei mai 'l' come nome di variabile. – tad

2

Questo è chiamato il bug di argomento predefinito mutabile che viene comunemente creato da persone nuove in Python. Quando si imposta un argomento mutabile come predefinito, lo stesso oggetto viene utilizzato tra le istanze quando è necessario utilizzare l'argomento predefinito. La ottenere una migliore comprensione controllare la sezione Avvertenza importante in http://docs.python.org/tutorial/controlflow.html#default-argument-values

Nel codice, l'istanza di un usato l'argomento di default mutabile (una lista oggetto vuoto) nella sua chiamata di init e quando è stata creata l'istanza di B, che a sua volta chiamato il metodo init di Base, usava di nuovo lo stesso oggetto usato nel suo init. Sulle parole più semplici a.l e b.l puntano allo stesso oggetto lista.

Una simile discussione - "Least Astonishment" and the Mutable Default Argument

+0

Non è un bug, è il modo in cui la lingua funziona. –

Problemi correlati