10

I am looking for practical and non-synthetic use cases of Python class decorators. So far, the only case which made sense to me is registering a class in a publisher-subscriber system, e.g. plugins or events, something like:

@register
class MyPlugin(Plugin):
    pass

or

@recieves_notifications
class Console:
    def print(self, text):
        ...

Any other sane cases I've been thinking of could have been built on top of inheritance, metaclasses or decorating methods. Could you please share any good (or bad!) examples of using class decorators?

Thank you!

4
  • For starters, decorators are conceptually much simpler than metaclasses. It is far simpler to write a decorator than a metaclass, and avoids possibly having to figure out how to combine multiple metaclasses without breaking anything.
    – amon
    Oct 20, 2016 at 21:57
  • @amon when a metaclass is used by a seasoned developer, it usually means that other options have been considered thoroughly and metaclass is so far the best way to solve the issue. Moreover, explicit is better than implicit - that's may be the reason why (as an example) we have ABCMeta, not @abstractclass class decorator. Oct 20, 2016 at 22:18
  • 2
    I'm a Python programmer, and I honestly don't see a need for them. Just because a language feature exists doesn't mean you have to or even should use it. Designers come up with all kinds of crazy features that turn out to have been unnecessary or even damaging with hindsight. In fact, you mentioned two other such features in your question :)
    – gardenhead
    Oct 21, 2016 at 2:52
  • 1
    Not someting I could not live without, but something I have found to be useful is to use a class decorator to log all the inputs and outputs of all the methods of the class.
    – bgusach
    Oct 29, 2016 at 21:27

4 Answers 4

9

When writing unit tests having the @unittest.skipIf and @unittest.skipUnless can be used on either individual methods or on an entire unittest.TestCase class definition. This makes for writing tests for platform specific problems so much easier.

Example from asyncio/test_selectors

# Some platforms don't define the select.kqueue object for these tests.
# On those platforms, this entire grouping of tests will be skipped.

@unittest.skipUnless(hasattr(selectors, 'KqueueSelector'),
                 "Test needs selectors.KqueueSelector)")
class KqueueSelectorTestCase(BaseSelectorTestCase, ScalableSelectorMixIn):
...
0
2

Class decorators were explicitly created to make some things that were already expressible via metaclasses more pleasant, from the PEP:

The motivating use-case was to make certain constructs more easily expressed and less reliant on implementation details of the CPython interpreter. While it is possible to express class decorator-like functionality using metaclasses, the results are generally unpleasant and the implementation highly fragile. In addition, metaclasses are inherited, whereas class decorators are not, making metaclasses unsuitable for some, single class-specific uses of class decorators. The fact that large-scale Python projects like Zope were going through these wild contortions to achieve something like class decorators won over the BDFL.

3
  • Thanks for citing PEP-3129. However the question is not about why class decorators exist, what Guido thinks of them, and how Zope or IronPython could have used them before they emerged. The question is about their practical usage today, in year 2016. Oct 25, 2016 at 19:36
  • 1
    Right, the point is that the original question brings up metaclasses as something that can be used to implement class-decorator-like functionality, but the entire point of decorators is that they're easier to use and more obvious than metaclasses. So the answer to that part of the question is "If you're torn between decorators or metaclasses, you should use decorators because they're easier for others to understand." Oct 28, 2016 at 18:38
  • You are leaving more questions that answers. "...the entire point of decorators is that they're easier to use and more obvious than metaclasses" - In which cases? Then "...you should use decorators because they're easier for others to understand" Really? For a long time of addiction to Python I've seen tons of metaclasses, some ugly, some beautiful. But have not discovered any class decorators at all. Oct 28, 2016 at 18:47
1

From this stack overflow question:

def singleton(class_):
  instances = {}
  def getinstance(*args, **kwargs):
    if class_ not in instances:
        instances[class_] = class_(*args, **kwargs)
    return instances[class_]
  return getinstance

@singleton
class MyClass(BaseClass):
  pass
1
  • Yep, but the contra is given right in the same SO question: the metaclass is a better approach. Oct 20, 2016 at 21:34
1

Looking for use cases that can be done with decorators on classes is futile - anything that can be done with decorators on classes can be done with metaclasses. Even your example of registration. To prove it, here is a metaclass that applies a decorator:

Python 2:

def register(target):
    print 'Registring', target
    return target


class ApplyDecorator(type):
    def __new__(mcs, name, bases, attrs):
        decorator = attrs.pop('_decorator')
        cls = type(name, bases, attrs)
        return decorator(cls)

    def __init__(cls, name, bases, attrs, decorator=None):
        super().__init__(name, bases, attrs)


class Foo:
    __metaclass__ = ApplyDecorator
    _decorator = register

Python 3:

def register(target):
    print('Registring', target)
    return target


class ApplyDecorator(type):
    def __new__(mcs, name, bases, attrs, decorator):
        cls = type(name, bases, attrs)
        return decorator(cls)

    def __init__(cls, name, bases, attrs):
        super().__init__(name, bases, attrs)


class Foo(metaclass=ApplyDecorator, decorator=register):
    pass
1
  • 1
    As you say - anything can be done with decorator. The question is, what are the cases which should be done via class decorators rather than metaclasses. Oct 23, 2016 at 19:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.