I don't know if I have a good design here, but I have a class that is derived from unittest.TestCase and the way I have it set up, my code will dynamically inject a bunch of test_*
methods into the class before invoking unittest to run through it. I use setattr
for this. This has been working well, but now I have a situation in which I want to remove the methods I previously injected and inject a new set of methods. How can I remove all the methods in a class whose names match the pattern test_*
?
Asked
Active
Viewed 2.0k times
18

tadasajon
- 14,276
- 29
- 92
- 144
4 Answers
29
-
@JasonSperske: Not if you have to delete an attribute whose name is computed programmatically. You can only use `del` to delete a name you can literally type in the source code. – BrenBarn May 22 '13 at 20:26
-
@JasonSperske -- the title says "opposite of setattr" implying that OP knows the method name as a string... – mgilson May 22 '13 at 20:26
-
The common usage for me is `delattr(type(obj), 'test_foo')` (for testing purposes only). A method cannot be unbound from a Class object, but only from the entire class(which affects all the objects) – Bryce Guinta Jun 18 '16 at 00:50
-
@BryceGuinta however, isn't it strange, that I can do st. like `foo.quack = lambda: "Quack"; print (foo.quack())` where *quack* was not defined so far for *foo*? – lef Oct 15 '17 at 22:22
-
@lef A method defined in a class is bound to the instance upon creation. You're setting a new attribute on an object which happens to be a function where the object happens to be an instance of a class. A bound method (which is defined in the class) implicitly passes the instance to the class's method (usually called self). Your function however does not do that – Bryce Guinta Oct 15 '17 at 22:59
-
But delattr delete attributes not methods... Trying to delete mathods will give you an attribute error – G M Jun 18 '21 at 14:49
-
@GM: Methods are attributes. – BrenBarn Jun 19 '21 at 18:57
6
>>> class Foo:
def func(self):
pass
...
>>> dir(Foo)
['__doc__', '__module__', 'func']
>>> del Foo.func
>>> dir(Foo)
['__doc__', '__module__']

Ashwini Chaudhary
- 244,495
- 58
- 464
- 504
2
As an addition to the previous answers: If the method to be deleted is re-implemented, you'd have to delete the subclass and parent class methods, both:
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
(Or use delattr
of @BrenBarn's answer)

DomTomCat
- 8,189
- 1
- 49
- 64
1
delattr()
is what you want. Loop through vars()
of the class and test for attribute names starting with "test_"
. E.g.,
@classmethod
def remove_test_methods(cls):
for name in list(vars(cls)):
if name.startswith("test_") and callable(getattr(cls, name)):
delattr(cls, name)
I'd advise against using dir()
, as this will show you names from your parent classes as well, so not all the names you get from dir()
may defined on the class you're targeting.

kindall
- 178,883
- 35
- 278
- 309
-
This looks good, however I got `RuntimeError: dictionary changed size during iteration` – tadasajon May 22 '13 at 20:36
-
Oh yeah, `vars()` is a dictionary even though I'm just using the keys. Let me fix that... – kindall May 22 '13 at 20:38
-
Yeah, as I say, you don't want `dir()` as it will find stuff in parent classes. – kindall May 22 '13 at 20:59