Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
261 views
in Technique[技术] by (71.8m points)

python - Is enforcing an abstract method implementation unpythonic?

When designing classes abstract methods can be very helpful. From what I know, Python does not have a mechanism for enforcing an inherited class to implement the abstract method. In my code (see example below) I enter a failed assertion in the base class to cause a runtime error if not implemented. Is this unpythonic?

class Dog(Animal):
  def speak(self):
   return "bark"

class Animal():
  def speak(self):
   assert(False) #abstract
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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"

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...