Decoratori di classe in Python: casi d'uso pratico

9

Sto cercando casi di utilizzo pratico e non sintetico dei decoratori di classe Python. Finora, l'unico caso che aveva senso per me è la registrazione di una classe in un sistema di sottoscrizione di editori, ad es. plugin o eventi, qualcosa del tipo:

@register
class MyPlugin(Plugin):
    pass

o

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

Qualsiasi altro caso sano che stavo pensando potrebbe essere stato costruito su ereditarietà, metaclassi o metodi di decorazione. Potresti per favore condividere qualche esempio valido (o cattivo!) Dell'uso di decoratori di classe?

Grazie!

    
posta Zaur Nasibov 20.10.2016 - 23:20
fonte

4 risposte

8

Quando scrivi i test unitari, hai @unittest.skipIf e @unittest.skipUnless può essere utilizzato su singoli metodi o su una definizione di classe unittest.TestCase completa. Questo rende molto più facile scrivere test per problemi specifici della piattaforma.

Esempio da 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):
...
    
risposta data 21.10.2016 - 18:11
fonte
3

I decoratori di classe sono stati creati esplicitamente per rendere più piacevoli alcune cose che erano già espresse tramite metaclassi, dal 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.

    
risposta data 25.10.2016 - 20:37
fonte
2

La ricerca di casi d'uso che possono essere fatti con i decoratori sulle classi è inutile - qualsiasi cosa che può essere fatto con decoratori sulle classi può essere fatto con metaclassi. Anche il tuo esempio di registrazione. Per dimostrarlo, ecco una metaclasse che applica un decoratore:

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
    
risposta data 21.10.2016 - 23:00
fonte
1

Da questa domanda di overflow dello stack:

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
    
risposta data 20.10.2016 - 23:32
fonte

Leggi altre domande sui tag