[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