2013-05-22 7 views
5

Non so se ho un buon design qui, ma ho una classe derivata da unittest.TestCase e il modo in cui io averlo impostato, il mio codice inserirà dinamicamente un gruppo di metodi test_* nella classe prima di richiamare l'unittest per eseguirlo. Io uso setattr per questo. Questo ha funzionato bene, ma ora ho una situazione in cui voglio rimuovere i metodi precedentemente iniettati e iniettare una nuova serie di metodi. Come posso rimuovere tutti i metodi in una classe i cui nomi corrispondono al modello test_*?Python - come posso rimuovere dinamicamente un metodo da una classe - cioè opposto di setattr

risposta

14

Si chiama delattr ed è documentato here.

+0

Non funziona anche "del"? –

+0

@JasonSperske: non se è necessario eliminare un attributo il cui nome viene calcolato a livello di codice. Puoi solo usare 'del' per cancellare un nome che puoi letteralmente digitare nel codice sorgente. – BrenBarn

+0

@JasonSperske - il titolo dice "opposto di setattr" implicando che OP conosce il nome del metodo come una stringa ... – mgilson

3
>>> class Foo: 
    def func(self): 
     pass 
...  
>>> dir(Foo) 
['__doc__', '__module__', 'func'] 
>>> del Foo.func 
>>> dir(Foo) 
['__doc__', '__module__'] 
1

delattr() è quello che vuoi. Passare attraverso vars() della classe e verificare i nomi degli attributi che iniziano con "test_". Per esempio,

@classmethod 
def remove_test_methods(cls): 
    for name in list(vars(cls)): 
     if name.startswith("test_") and callable(getattr(cls, name)): 
      delattr(cls, name) 

vorrei consigliare di non usare dir(), in quanto questo vi mostrerà i nomi dei tuoi classi genitore e, in modo non tutti i nomi che si ottiene da dir() possono definita sulla classe che stai targeting.

+0

Questo aspetto sembra buono, tuttavia ho ottenuto 'RuntimeError: dizionario ha cambiato le dimensioni durante l'iterazione' – jononomo

+0

Oh sì,' vars() 'è un dizionario anche se sto solo usando i tasti. Lasciatemi aggiustare che ... – kindall

+0

'dir (cls)' forse? – thkang

0

In aggiunta alle risposte precedenti: se il metodo da cancellare è re-implementato, che avrebbe dovuto eliminare i metodi della classe sottoclasse e genitori, entrambi:

class A: 
    def method(self): 
     print("TestA") 

class B(A): 
    def method(self): 
     A.method(self) 
     print("TestB") 

instance = B() 
instance.method() # will call B.method() 
del B.method 
instance.method() # will now call A.method() 
del A.method 
instance.method() # will now raise AttributeError 

(o usare delattr di @ Risposta di BrenBarn)

Problemi correlati