[Python-ideas] method decorators @final and @override in Python 2.4

Scott David Daniels Scott.Daniels at Acm.Org
Sun Mar 29 09:16:54 CEST 2009


Scott David Daniels wrote:
> Péter Szabó wrote:
>> If Python had method decorators @final (meaning: it is an error to
>> override this method in any subclass) and @override (meaning: it is an
>> error not having this method in a superclass), I would use them in my
>> projects (some of them approaching 20 000 lines of Python code) and
>> I'll feel more confident writing object-oriented Python code....
> 
> I have no idea why you want these, and severe trepidation about
> dealing with code that uses them "just to be safe."  It smacks of
> the over-use I see of doubled underscores.  For @override, just
> because you've built a base class for one kind of object does not
> mean I have not thought of an interesting way to use 40% of your
> code to accomplish my own end.  Why make me cut and paste?  You
> are not responsible for the correctness of my flea-brained idea
> whether I inherit from your class or not.  For @final, "how dare
> you" for similar reasons.  Java at least has an excuse (compilation
> can proceed differently).

I was asked off-group to give an example where use of @override
prevents reusing some code.  First, the above is an overstatement
of my case, probably an attempt to "bully" you off that position.
For that bullying, I apologize.  Second, what follows below is one
example of what @overrides prevents me from doing.  Say you've
built a class named "MostlyAbstract" with comparisons:

     class MostlyAbstract(object):
         @override
         def __hash__(self, other):
             pass
         @override
         def __lt__(self, other):
             pass
         @override
         def __eq__(self, other):
             pass
         def __le__(self, other):
             return self.__lt__(other) or self.__eq__(other)
         def __gt__(self, other):
             return other.__lt__(self)
         def __ge__(self, other):
             return self.__gt__(other) or self.__eq__(other)

and I decide the comparison should works a bit differently:

     class MostAbstract(MostlyAbstract):
         def __gt__(self, other):
             return not self.__le__(self)


This choice of mine won't work, even when I'm trying to just do a
slight change to your abstraction.  Similarly, If I want to
monkey-path in a debugging print or two, I cannot do it without
having to create a bunch of vacuous implementations.  Also, a
@final will prevent me from sneaking in aextra print when I'm
bug-chasing.

That being said, a mechanism like the following could be used
as a facility to implement your two desires, by providing a nice
simple place called as each class definition is completed:

class Type(type):
     '''A MetaClass to call __initclass__ for freshly defined classes.'''
     def __new__(class_, name, supers, methods):
         if '__initclass__' in methods and not isinstance(
                             methods['__initclass__'], classmethod):
             method = methods['__initclass__']
             methods['__initclass__'] = classmethod(method)
         return type.__new__(class_, name, supers, methods)

     def __init__(self, name, supers, methods):
         type.__init__(self, name, supers, methods)
         if hasattr(self, '__initclass__'):
             self.__initclass__()


In 2.5, for example, you'd use it like:

class Foo(SomeParent):
     __metaclass__ = Type

     def __init_class__(self):
         <check for whatever you like.>

--Scott David Daniels
Scott.Daniels at Acm.Org




More information about the Python-ideas mailing list