2016-01-05 14 views
5

Consideriamo qualsiasi classe pitonica definita dall'utente. Se chiamo dir(obect_of_class), ho la lista dei suoi attributi:Modifica della funzione built-in

['__class__', '__delattr__', '__dict__', '__dir__', ... '__weakref__', 'bases', 
'build_full_name', 'candidates', ... 'update_name']. 

si possono vedere 2 tipi di attributi in questa lista:

  • attributi built-in,
  • definito dall'utente.

Devo eseguire l'override di __dir__ in modo che restituisca solo attributi definiti dall'utente. Come posso farlo?

E 'chiaro che se in una funzione sovrascritta mi chiamo, mi dà una ricorsione infinita. Quindi, voglio fare qualcosa del genere:

def __dir__(self): 
     return list(filter(lambda x: not re.match('__\S*__', x), dir(self))) 

ma eludere la ricorsione infinita.

In generale, come è possibile modificare una funzione incorporata se non si desidera scriverla da zero ma si desidera modificare la funzione esistente?

+0

Hai provato a utilizzare 'dir (ClassName)'? – DainDwarf

risposta

8

Utilizzare super per chiamare l'implementazione genitore di __dir__; evitare la ricorsione:

import re 


class AClass: 

    def __dir__(self): 
     return [x for x in super().__dir__() if not re.match(r'__\S+__$', x)] 

    def method(self): 
     pass 

>>> dir(AClass()) 
['method'] 
+0

Perché usare i generatori è meglio che usare 'lista (filtro ...))'? – VeLKerr

+1

@VeLKerr, non è un generatore, ma una lista di comprensione. Per me è molto più facile da leggere. – falsetru

+0

Ok, funziona, ma è molto strano perché 'super()' -object non ha campi definiti dall'utente. Quindi, potresti spiegare, * perché * funziona? – VeLKerr

2

Vuoi farlo per classe personalizzata o globalmente per dir() funzione?

Primo approccio (classe solo):

class MyClass: 
    def f(self): 
     return None 

    def __dir__(self): 
     return list(filter(lambda x: not re.match('__\S*__', x), super().__dir__())) 


print(dir(MyClass())) # ['f'] 

Fondamentalmente ciò che è fatto qui sta chiamando __dir__() della superclasse (non classe stessa) e filtrando in sottoclasse.

Secondo approccio (shadowing funzione dir globale):

import re 


def dir(obj): 
    return list(filter(lambda x: not re.match('__\S*__', x), __builtins__.dir(obj))) 

print(dir({})) # ['clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values'] 

Ecco tutte le chiamate al dir() sarebbe filtrato. Come puoi vedere, funzionerà per tutti i tipi, inclusi i tipi built-in.

+0

Voglio sovrascrivere '__dir() __' solo per la mia classe, ma grazie mille per la spiegazione dello shadowing globale. Post scriptum 'super()' funziona per me anche senza argomenti (ho modificato il post). – VeLKerr