[Python-ideas] Decorator to avoid a mistake

Nick Coghlan ncoghlan at gmail.com
Sat Nov 26 02:16:21 EST 2016


On 26 November 2016 at 13:26, Guido van Rossum <guido at python.org> wrote:
> I think one reason why such proposals are unwelcome to experienced users may
> be that when done right this is totally legitimate, and the requirement to
> use an @override decorator is just making code more verbose with very little
> benefit.

It's also the case that if we're going to provide decorators to help
with class definitions, there are more valuable things that we can do
beyond merely warning about accidental method and attribute overrides.

For example, I've recently started using Hynek Schlawack's attrs
project, which pairs up an "attr.attributes" class decorator with an
"attr.attrib()" descriptor to make the following a class definition
with totally ordered instances and a nice repr() implementation:

    @attributes
    class MyClass:
        attr1 = attrib()
        attr2 = attrib()
        ...

It's *really* nice to use, and means I'm more inclined to define
explicit helper classes for interim results rather than passing
convenient-but-hard-to-debug raw tuples, lists and dicts around.

The docs summarise the special method implementations that the
decorator will inject for you in
https://attrs.readthedocs.io/en/stable/why.html#hand-written-classes
and go into more details on how it works at
https://attrs.readthedocs.io/en/stable/how-does-it-work.html

While the focus of attrs itself is very much on defining data
structures where composition is the main form of re-use rather than
inheritance, subclassing *is* supported, and such a system could also
be used to complain about accidental attribute and method name
collisions.

Integrating a check for accidental overrides with a method-boilerplate
reduction class decorator like the one in attrs would help address a
few potential objections:

- undecorated class definitions would be unaffected, so there'd be no
start-up performance hit for existing code
- leaving out the decorator when you intended to use it would also
mean you wouldn't have an __init__ method defined, so you'd notice
pretty fast if you forgot to use it
- for the cost of some explicit decorators on the class definition and
any method overrides, you get to skip writing a whole set of special
methods (__new__/__init__, __repr__/etc, __eq__/__ne__, __lt__/etc)

The specific names from the attrs project wouldn't be suitable for the
standard library, but something like the following might work:

    @autoinit
    class MyClass:
        attr1 = instanceattr()
        attr2 = instanceattr()

Where "instanceattr" is inspired by "classmethod" and "staticmethod",
while "autoinit" refers directly to the main benefit of the class
decorator (i.e. it writes your __init__ method for you based on the
"instanceattr" definitions).

The standardised variant of that could be kept very simple, while more
advanced features like data validation and conversion were left to
third party libraries like attrs.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia


More information about the Python-ideas mailing list