How do you "disable" the __call__
method on a subclass so the following would be true:
class Parent(object):
def __call__(self):
return
class Child(Parent):
def __init__(self):
super(Child, self).__init__()
object.__setattr__(self, '__call__', None)
>>> c = Child()
>>> callable(c)
False
This and other ways of trying to set __call__
to some non-callable value still result in the child appearing as callable.
You can't. As jonrsharpe points out, there's no way to make Child
appear to not have the attribute, and that's what callable(Child())
relies on to produce its answer. Even making it a descriptor that raises AttributeError
won't work, per this bug report: https://bugs.python.org/issue23990 . A python 2 example:
>>> class Parent(object):
... def __call__(self): pass
...
>>> class Child(Parent):
... __call__ = property()
...
>>> c = Child()
>>> c()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: unreadable attribute
>>> c.__call__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: unreadable attribute
>>> callable(c)
True
This is because callable(...)
doesn't act out the descriptor protocol. Actually calling the object, or accessing a __call__
attribute, involves retrieving the method even if it's behind a property, through the normal descriptor protocol. But callable(...)
doesn't bother going that far, if it finds anything at all it is satisfied, and every subclass of Parent will have something for __call__
-- either an attribute in a subclass, or the definition from Parent
.
So while you can make actually calling the instance fail with any exception you want, you can't ever make callable(some_instance_of_parent)
return False.
It's a bad idea to change the public interface of the class so radically from the parent to the base.
As pointed out elsewhere, you cant uninherit __call__
. If you really need to mix in callable and non callable classes you should use another test (adding a class attribute) or simply making it safe to call the variants with no functionality.
To do the latter, You could override the __call__
to raise NotImplemented
(or better, a custom exception of your own) if for some reason you wanted to mix a non-callable class in with the callable variants:
class Parent(object):
def __call__(self):
print "called"
class Child (Parent):
def __call__(self):
raise NotACallableInstanceException()
for child_or_parent in list_of_children_and_parents():
try:
child_or_parent()
except NotACallableInstanceException:
pass
Or, just override call with pass:
class Parent(object):
def __call__(self):
print "called"
class Child (Parent):
def __call__(self):
pass
Which will still be callable but just be a nullop.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With