How about "pure virtual methods"?

Alex Martelli aleaxit at yahoo.com
Sat Dec 18 21:58:14 EST 2004


Noam Raphael <noamr at remove.the.dot.myrea.lbox.com> wrote:

> What I want is that if I have this module:
> 
> ======================
> 
> class BaseClass(object):
>      def __init__(self):
>          ...
> 
>      @notimplemented
>      def save_data(self, filename):
>          """This method should save the internal state of the class to
>          a file named filename.
>          """
>          pass
> 
> class RealClass(BaseClass):
>      def save_data(self, filename):
>          open(filename).write(self.data)
> 
> ======================
> 
> then if I try to instantiate BaseClass I would get an exception, but 
> instantiating RealClass will be ok.
> 
> 
> Well, what do you say?

It's already easy to do as long as you don't insist that BaseClass must
subclass object (or allow a __metaclass__ assignment there).  Basically,
what you describe is the job of a custom metaclass, because that's where
the __call__ method on classes is defined (classes being instances of
the metaclass)... much cleaner than tampering with the __new__ or
__init__ at class level.

At sketch level, you'd have, say:

def notimplemented(f):
    # save some data about f somewhere if you wish, then, e.g.:
    return notimplemented

import inspect

class Meta_for_NR(type):
    def __init__(cls, cn, cb, cd):
        super(Meta_for_NR, cls).__init__(cn, cb, cd)
        abstract_methods = []
        for n, v in inspect.getmembers(cls, inspect.ismethod):
            if v is notimplemented: abstract_methods.append(n)
        cls._abstract_methods = abstract_methods
    def __call__(cls, *a, **k):
        if cls._abstract_methods:
            raise TypeError, ("Cannot instantiate abstract class %s."
                " Abstract methods: %s." % (cls.__name__,
                ', '.join(cls._abstract_methods)))
        return super(Meta_for_NR, cls).__call__(*a, **k)

class Base_for_NR: __metaclass__ = Meta_for_NR


Inheriting from Base_for_NR instead of inheriting from object should
give you just the behavior you desire (net of the fact that this code of
mine is untested, just a sketch -- but the key ideas shd be ok).


If you can implement this and get it into wide usage, it may well be
adopted in the standard library.  Unless there is proof by experience
that a lot of people like this approach better than the de facto
standard, such adoption is very unlikely.  But the great thing is that
it's EASY to implement your ideas and try to garner a following for
them, so you stand a chance to get them into the standard library if you
can prove they really work well and are well-liked!


Alex



More information about the Python-list mailing list