Decoradores de classe em Python: casos de uso prático


9

Estou procurando casos de uso práticos e não sintéticos de decoradores de classe Python. Até agora, o único caso que fez sentido para mim é o registro de uma classe em um sistema de editor-assinante, por exemplo, plugins ou eventos, algo como:

@register
class MyPlugin(Plugin):
    pass

ou

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

Quaisquer outros casos sensatos em que estive pensando poderiam ter sido construídos sobre herança, metaclasses ou métodos de decoração. Você poderia compartilhar exemplos bons (ou ruins!) Do uso de decoradores de classe?

Obrigado!


Para iniciantes, os decoradores são conceitualmente muito mais simples que as metaclasses. É muito mais simples escrever um decorador do que uma metaclasse e evita ter que descobrir como combinar várias metaclasses sem quebrar nada.
amon

@ amon quando uma metaclasse é usada por um desenvolvedor experiente, geralmente significa que outras opções foram consideradas minuciosamente e a metaclasse é a melhor maneira de resolver o problema. Além disso, explícito é melhor do que implícito - essa pode ser a razão pela qual (como exemplo) temos ABCMeta, não o @abstractclassdecorador de classes.
Zaur Nasibov

2
Sou um programador Python e honestamente não vejo necessidade deles. Só porque um recurso de linguagem existe, não significa que você precisa ou deve usá-lo. Os designers criam todos os tipos de recursos malucos que acabam sendo desnecessários ou até prejudiciais em retrospectiva. Na verdade, você mencionou outras duas dessas características em sua pergunta :)
gardenhead

11
Não é algo que eu não poderia viver sem, mas algo que eu achei útil é usar um decorador de classe para registrar todas as entradas e saídas de todos os métodos da classe.
bgusach

Respostas:


8

Ao escrever testes de unidade com @unittest.skipIfe @unittest.skipUnlesspode ser usado em métodos individuais ou em uma unittest.TestCasedefinição de classe inteira . Isso facilita muito a criação de testes para problemas específicos da plataforma.

Exemplo de 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

Decoradores de classe foram criados explicitamente para tornar mais agradáveis ​​algumas coisas que já eram expressáveis ​​através de metaclasses, do PEP :

O caso de uso motivador foi tornar certas construções mais facilmente expressas e menos dependentes dos detalhes de implementação do interpretador CPython. Embora seja possível expressar a funcionalidade de decorador de classe usando metaclasses, os resultados geralmente são desagradáveis ​​e a implementação altamente frágil. Além disso, as metaclasses são herdadas, enquanto os decoradores de classe não são, tornando as metaclasses inadequadas para alguns usos específicos de classe de decoradores de classe. O fato de que projetos Python em larga escala como o Zope estavam passando por essas contorções malucas para conseguir algo como decoradores de classe conquistaram o BDFL.


Obrigado por citar o PEP-3129. No entanto, a questão não é sobre por que os decoradores de classe existem, o que Guido pensa deles e como o Zope ou o IronPython poderiam tê-los usado antes de surgirem. A questão é sobre seu uso prático hoje, no ano de 2016.
Zaur Nasibov 25/10/16

11
Certo, o ponto é que a pergunta original traz as metaclasses como algo que pode ser usado para implementar a funcionalidade de decorador de classe, mas o ponto principal dos decoradores é que eles são mais fáceis de usar e mais óbvios do que as metaclasses. Portanto, a resposta para essa parte da pergunta é "Se você está dividido entre decoradores ou metaclasses, deve usar decoradores, porque são mais fáceis para os outros entenderem".
quodlibetor

Você está deixando mais perguntas que respondem. "... o ponto principal dos decoradores é que eles são mais fáceis de usar e mais óbvios que as metaclasses" - Em quais casos? Então "... você deve usar decoradores porque é mais fácil para os outros entenderem" Sério? Por um longo tempo viciado em Python, vi toneladas de metaclasses, algumas feias, outras bonitas. Mas ainda não descobrimos nenhum decorador de classe.
Zaur Nasibov 28/10

1

A partir dessa pergunta de estouro de pilha:

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

Sim, mas o contrário é dado exatamente na mesma pergunta do SO: a metaclasse é uma abordagem melhor.
Zaur Nasibov

1

É inútil procurar casos de uso que possam ser feitos com decoradores em classes - qualquer coisa que possa ser feita com decoradores em classes pode ser feita com metaclasses. Até o seu exemplo de registro. Para provar isso, aqui está uma metaclasse que aplica um decorador:

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

11
Como você diz - tudo pode ser feito com o decorador. A questão é: quais são os casos que devem ser feitos por decoradores de classe, e não por metaclasses.
Zaur Nasibov 23/10
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.