Decoratori di classe in Python: casi d'uso pratici


9

Sto cercando casi d'uso pratici e non sintetici di decoratori di classe Python. Finora, l'unico caso che ha avuto senso per me è la registrazione di una classe in un sistema editore-abbonato, ad esempio plugin o eventi, qualcosa come:

@register
class MyPlugin(Plugin):
    pass

o

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

Qualsiasi altro caso sensato a cui stavo pensando avrebbe potuto essere costruito sulla base di eredità, metaclassi o metodi di decorazione. Potresti condividere qualche esempio positivo (o negativo!) Sull'uso dei decoratori di classe?

Grazie!


Per i principianti, i decoratori sono concettualmente molto più semplici dei metaclassi. È molto più semplice scrivere un decoratore che una metaclasse ed evita possibilmente di dover capire come combinare più metaclasse senza rompere nulla.
amon

@amon quando una metaclasse viene utilizzata da uno sviluppatore esperto, di solito significa che altre opzioni sono state considerate attentamente e la metaclasse è finora il modo migliore per risolvere il problema. Inoltre, esplicito è meglio di implicito - questo potrebbe essere il motivo per cui (come esempio) abbiamo ABCMeta, non un @abstractclassdecoratore di classe.
Zaur Nasibov,

2
Sono un programmatore Python e sinceramente non ne vedo la necessità. Solo perché esiste una funzione linguistica non significa che devi o addirittura dovresti usarla. I progettisti escogitano tutti i tipi di funzionalità folli che risultano inutili o addirittura dannose con il senno di poi. In effetti, hai menzionato altre due caratteristiche simili nella tua domanda :)
gardenhead

1
Non qualcosa in cui non potrei vivere senza, ma qualcosa che ho trovato utile è usare un decoratore di classe per registrare tutti gli input e gli output di tutti i metodi della classe.
bgusach,

Risposte:


8

Quando si scrivono unit test con @unittest.skipIfe @unittest.skipUnlesspossono essere utilizzati su singoli metodi o su un'intera unittest.TestCasedefinizione di classe. Ciò rende molto più semplice la scrittura di 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):
...

2

I decoratori di classe sono stati creati esplicitamente per rendere più piacevoli alcune cose che erano già esprimibili tramite metaclassi, dal PEP :

Il caso d'uso motivante era quello di rendere alcuni costrutti più facilmente espressi e meno dipendenti dai dettagli di implementazione dell'interprete CPython. Mentre è possibile esprimere la funzionalità di un decoratore di classe usando metaclassi, i risultati sono generalmente spiacevoli e l'implementazione estremamente fragile. Inoltre, i metaclassi sono ereditati, mentre i decoratori di classe non lo sono, il che rende i metaclassi inadatti per alcuni usi specifici di una classe di decoratori di classe. Il fatto che progetti Python su larga scala come Zope stessero attraversando queste contorsioni selvagge per ottenere qualcosa come i decoratori di classe ha conquistato il BDFL.


Grazie per aver citato PEP-3129. Tuttavia, la domanda non riguarda il motivo per cui esistono i decoratori di classe, cosa ne pensa Guido di loro e come Zope o IronPython avrebbero potuto usarli prima che emergessero. La domanda riguarda il loro uso pratico oggi, nell'anno 2016.
Zaur Nasibov,

1
Giusto, il punto è che la domanda originale fa apparire le metaclasse come qualcosa che può essere usato per implementare la funzionalità di un decoratore di classe, ma il punto centrale dei decoratori è che sono più facili da usare e più ovvi delle metaclasse. Quindi la risposta a quella parte della domanda è "Se sei diviso tra decoratori o metaclassi, dovresti usare i decoratori perché sono più facili da capire per gli altri".
quodlibetor,

Stai lasciando più domande che rispondono. "... il punto centrale dei decoratori è che sono più facili da usare e più ovvi dei metaclassi" - In quali casi? Quindi "... dovresti usare i decoratori perché sono più facili da capire per gli altri" Davvero? Per molto tempo ho avuto dipendenza da Python ho visto tonnellate di metaclassi, alcune brutte, altre belle. Ma non ho scoperto nessun decoratore di classe.
Zaur Nasibov,

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

Sì, ma il contra è dato esattamente nella stessa domanda SO: la metaclasse è un approccio migliore.
Zaur Nasibov,

1

Cercare casi d'uso che possono essere eseguiti con i decoratori durante le lezioni è inutile: tutto ciò che può essere fatto con i decoratori durante le lezioni 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

1
Come dici tu, tutto può essere fatto con decoratore. La domanda è: quali sono i casi che dovrebbero essere fatti tramite decoratori di classe piuttosto che metaclassi.
Zaur Nasibov,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.