callable virtual method

  • Thread starter Jean-Michel Pichavant
  • Start date
J

Jean-Michel Pichavant

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.

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()

It works but it's tedious, I have to add these 2 lines to every virtual
method, changing the content of the 2 lines.

Maybe there is a nice/builtin way to do so (python 2.4)

JM
 
D

Diez B. Roggisch

Jean-Michel Pichavant said:
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.

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()

It works but it's tedious, I have to add these 2 lines to every virtual
method, changing the content of the 2 lines.

Maybe there is a nice/builtin way to do so (python 2.4)

Python has no concept of "virtual" methods. A simple


class Stream(object):


def resetStats(self):
raise NotImplemented


is all you need. Once a subclass overrides resetStats, that
implementatino is used.

Additionally, there are modules such as zope.interface out there, that
let you define more formally what an interface is, and declare who's
implementing it. I don't used this myself though, so I can't really
comment to which extend it e.g. warns you if you subclass *without*
implementing.

Diez
 
S

Steven D'Aprano

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,185
Members
46,736
Latest member
AdolphBig6

Latest Threads

Top