
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@Acm.Org