callable virtual method
Steven D'Aprano
steve at REMOVE-THIS-cybersource.com.au
Fri Aug 14 11:56:27 EDT 2009
On Fri, 14 Aug 2009 16:49:47 +0200, Jean-Michel Pichavant wrote:
> Hi fellows,
>
> Does anyone know a way to write virtual methods (in one virtual class)
> that will raise an exception only if called without being overridden ?
> Currently in the virtual method I'm checking that the class of the
> instance calling the method has defined that method as well.
I'm not entirely sure of the terminology -- is this the same as an
abstract base class? Googling has not enlightened me. Given your example,
it seems to be.
> Example:
>
> class Stream(object):
> """Interface of all stream objects"""
> def resetStats(self):
> """Reset the stream statistics. All values a zeroed except the
> date."""
> _log.info('Reset statistics of %s' % self)
> if self.__class__.resetStats == Stream.resetStats:
> raise NotImplementedError()
The usual idiom I've seen for abstract methods is to simplify the check,
and to put it *before* any work is done:
class Stream(object):
"""Interface of all stream objects"""
def resetStats(self):
if self.__class__ is Stream:
raise NotImplementedError()
_log.info('Reset statistics of %s' % self)
Even simpler is to just put the check in __init__, so to prevent the
caller from creating an instance of the class:
class AbstractStream(object):
def __init__(self):
if self.__class__ is Stream:
raise NotImplementedError('abstract class')
def resetStats(self):
# This does not need to be over-ridden.
_log.info('Reset statistics of %s' % self)
def whatever(self):
# This *must* be over-ridden, and *cannot* be called
raise NotImplementedError('abstract method')
If you have a lot of methods, you can probably reduce the boilerplate
with decorators:
# Untested
from functools import wraps
def abstract(func):
# Abstract methods don't have to be over-ridden, so long as they
# are called from a subclass of the abstract class.
@functools.wraps(func)
def inner(self, *args, **kwargs):
if self.__class__ is Stream:
raise NotImplementedError()
return func(self, *args, **kwargs)
return inner
def virtual(func):
# Virtual methods must be over-ridden, and must not be called by
# inheritance.
@functools.wraps(func)
def inner(self, *args, **kwargs):
raise NotImplementedError()
return inner
class Stream(object):
@abstract
def __init__(self):
pass
def resetStats(self):
_log.info('Reset statistics of %s' % self)
@virtual
def whatever(self):
pass
--
Steven
More information about the Python-list
mailing list