2016-02-10 18 views
9

Il seguente codice si comporta in modo diverso in Python 2 e Python 3 e non sono sicuro del perché.Differenza in "dir" tra Python 2 e 3

class Dataset(object): 
    def __getattr__(self, item): 
     if not item in dir(self): 
      print(item) 

a = Dataset() 
a.Hello 

Il risultato in Python 3:

> Hello 

Il risultato in Python 2:

__members__ 
__members__ 
__methods__ 
... 

all'infinito finché è raggiunto un massimale ricorsione. Qual è la differenza nel comportamento di "dir"?

Modifica: E c'è una soluzione? se stesso. dict è la scelta più ovvia ma non include funzioni che si rivelano essere un problema nel mio codice.

+2

In realtà, '__getattr __()' [non dovrebbe essere chiamato affatto] (https://docs.python.org/2/reference/datamodel.html#object.__getattr__) se l'attributo è già presente. – dhke

risposta

6

La documentazione per dir in Python 2.7 e 3.5 sembra identico - non ci sono dettagli di implementazione. Ma chiaramente, dir() in Python 2 invoca __getattr__ causando la ricorsione infinita.

Tuttavia, entrambi i set di documentazione non dicono che

Perché dir() viene fornito in primo luogo come vantaggio per l'uso in un prompt interattivo, esso cerca di fornire una interessante serie di nomi di più di quanto si cerca di fornire un insieme di nomi rigorosamente o coerentemente definito, e il suo comportamento dettagliato può cambiare tra le versioni. Ad esempio, gli attributi metaclass non sono nella lista dei risultati quando l'argomento è una classe.

Quella nota a proposito di comodità è significativa.

Se si modifica il __getattr__ per cercare self.__dict__ invece di utilizzare dir(), il problema scompare.

In [5]: class Dataset(object): 
      def __getattr__(self, item): 
      if not item in self.__dict__: 
       print(item) 
    ...:    

In [6]: a = Dataset() 

In [7]: a.Hello 
Hello 
+1

Non ho visto la modifica delle funzioni fino a dopo aver postato la risposta – kdopen

+1

AFAIR, 'dir()' prova a cercare '__dir__'. Dal momento che quello non esiste, viene chiamato '__getattr __()'. Che chiama 'dir()' ... – dhke

3

senza esaminare il codice sorgente, non posso dire perché questo accade (anche se ho alcune ipotesi), ma qui è una soluzione piuttosto semplice:

class Dataset(object): 
    def __getattr__(self, item): 
     try: 
      super(Dataset, self).__getattr__(item) 
     except AttributeError: 
      print(item) 
1

Non è necessario controllare che if not item in dir(self) all'interno def __getattr__

__getattr__ non sarà chiamato se l'oggetto è quotata in dir (auto) Si può avere il codice come

class Dataset(object): 
    x = 12 
    def __getattr__(self, item): 
     print(item) 

a = Dataset() 
a.Hello # print Hello 
a.x  # return 12 
Problemi correlati