callable virtual method

Discussion in 'Python' started by Jean-Michel Pichavant, Aug 14, 2009.

  1. 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
     
    Jean-Michel Pichavant, Aug 14, 2009
    #1
    1. Advertising

  2. Jean-Michel Pichavant schrieb:
    > 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
     
    Diez B. Roggisch, Aug 14, 2009
    #2
    1. Advertising

  3. 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
     
    Steven D'Aprano, Aug 14, 2009
    #3
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. jlopes
    Replies:
    7
    Views:
    448
    jlopes
    Nov 19, 2004
  2. Edward Diener

    Static method object not callable

    Edward Diener, Aug 11, 2004, in forum: Python
    Replies:
    8
    Views:
    762
    gblandst
    Mar 27, 2008
  3. exiquio
    Replies:
    2
    Views:
    565
    exiquio
    Oct 7, 2008
  4. Jean-Michel Pichavant

    Re: callable virtual method

    Jean-Michel Pichavant, Aug 14, 2009, in forum: Python
    Replies:
    12
    Views:
    422
    Bruno Desthuilliers
    Aug 17, 2009
  5. Ulrich Eckhardt
    Replies:
    6
    Views:
    141
    Peter Otten
    Jul 12, 2013
Loading...

Share This Page