Is Enforcing An Abstract Method Implementation Unpythonic?
Solution 1:
Python actually does have abstract classes with abstact methods:
>>> import abc
>>>
>>> class IFoo(object):
... __metaclass__ = abc.ABCMeta
...
... @abc.abstractmethod
... def foo(self):
... pass
...
>>> foo = IFoo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Cant instantiate abstract class IFoo with abstract methods foo
>>> class FooDerived(IFoo):
... pass
...
>>> foo = FooDerived()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Cant instantiate abstract class FooDerived with abstract methods foo
>>> class FooImplements(FooDerived):
... def foo(self):
... print "foo'ed"
...
>>> foo = FooImplements()
>>> foo.foo()
foo'ed
>>>
On the other hand, the fundamental question of "is this pythonic" is a bit harder to say. If your intent is to provide the abstract base class so that you can later check to make sure that values inherit from it, then no, that's not particularly pythonic, even though it's possible to make arbitrary types abstract subclasses of your baseclass. On the other hand, it's perfectly fine to provide an abstract baseclass that implements some functionality based upon the implementation provided in concrete subclasses. For example, collections.Sequence
and collections.Mapping
do just this for list like and dict like classes; subclasses can provide __getitem__
and can get __contains__
and others for free.
For certain, you should never use assert()
except to document the expectations of code; If it's actually possible for the assert to fail, you shouldn't be using an assert. Optimized python (python -O script.py
) does not check assertions.
Edit: more exposition:
If you are checking the type of a value:
def foo(bar):
if not isinstance(bar, AbstractBaz):
raise ValueError, ("bar must be an instance of AbstractBaz, "
"got %s" % type(bar))
If for some reason you can't use @abstractmethod
, but still want that effect, you should raise NotImplementedError
. You might want to do this because you actually do want instances of that class, some of which might not need to implement optional functionality. You still should account for the possibility that the function was called through super()
. To a first approximation, that might look like this.
class Foo(object):
def bar(self, baz):
if self.bar.im_func == Foo.bar.im_func:
raise NotImplementedError, "Subclasses must implement bar"
Solution 2:
ABCs are an artifact of C++ and are contrary to duck-typing. If class Animal did not define speak
it would do what you intend with no effort at all.
>>> class Animal(object):
... pass
...
>>> class Dog(Animal):
... def speak(self):
... print "bark"
...
>>> animal = Animal()
>>> dog = Dog()
>>> animal.speak()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Animal' object has no attribute 'speak'
>>> dog.speak()
bark
C++ and related languages force you to create ABCs because the ABC is actually an interface description. Python eschews compiler-enforced interface declarations as they attempt to document – in code – a contract that is better enforced through extra-linguistic means.
Solution 3:
Well, if you don’t include the method speak
in your base class and somehow happen to use it, the code fails anyway. The question is, how probable is it and how to tell the user (a NotImplementedError
might fit better here than an assertion).
Solution 4:
With python in general it can be not always possible to directly enforce restrictions on the code, at least from the object oriented point of view (thinking about abstract classes, private methods, ...). To enforce a subclass to implement a method you may want to do something like:
class Animal():
def speak(self):
raise NotImplementedError #abstract
class Dog(Animal):
def speak(self):
return "bark"
class MuteAnimal(Animal):
pass
This doesn't imply that the method will be implemented by the subclass, but it will simply raise an error when the speak method is not implemented.
Post a Comment for "Is Enforcing An Abstract Method Implementation Unpythonic?"