Pythonのクラスデコレーター:実用的なユースケース


9

私は、Pythonクラスデコレータの実用的で非合成の使用例を探しています。これまでのところ、私にとって意味のある唯一のケースは、次のようなプラグインやイベントなど、パブリッシャーサブスクライバーシステムにクラスを登録することです。

@register
class MyPlugin(Plugin):
    pass

または

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

私が考えていた他の正気なケースは、継承、メタクラス、または装飾メソッドの上に構築された可能性があります。クラスデコレータの使用例を教えてください。

ありがとうございました!


手始めに、デコレータは概念的にメタクラスよりもはるかに単純です。メタクラスよりもデコレータを書く方がはるかに簡単で、何も壊さずに複数のメタクラスを組み合わせる方法を理解する必要がなくなる可能性があります。
2016年

@amonは、熟練した開発者がメタクラスを使用する場合、通常、他のオプションが徹底的に検討されており、これまでのところ、メタクラスが問題を解決するための最良の方法です。さらに、明示的の方が暗黙的よりも優れています。これがABCMeta、(例として)@abstractclassクラスデコレータではなくを使用する理由である可能性があります。
Zaur Nasibov 2016年

2
私はPythonプログラマーであり、正直なところ、それらの必要性を感じていません。言語機能が存在するからといって、それを使用する必要がある、または使用する必要があるという意味ではありません。デザイナーはあらゆる種類のクレイジーな機能を思い付きますが、それらは不要であるか、あるいは後から見た場合でも害を及ぼすものです。実際、あなたはあなたの質問でそのような他の2つの機能について言及しました:)
gardenhead

1
なくてはなりませんが、クラスデコレータを使用して、クラスのすべてのメソッドのすべての入力と出力をログに記録することが有用であることがわかりました。
bgusach

回答:


8

@unittest.skipIfおよびを含む単体テストを作成する場合@unittest.skipUnless、個々のメソッドまたはunittest.TestCaseクラス定義全体のいずれかで使用できます。これにより、プラットフォーム固有の問題のテストを非常に簡単に作成できます。

からの例 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

クラスデコレータは、メタクラスを介してすでに表現可能だったいくつかのことをPEPからより快適にするために明示的に作成されました。

動機付けのユースケースは、特定の構成要素をより簡単に表現し、CPythonインタープリターの実装の詳細にあまり依存しないようにすることでした。メタクラスを使用してクラスデコレータのような機能を表現することは可能ですが、結果は一般的に不快であり、実装は非常に脆弱です。さらに、メタクラスは継承されますが、クラスデコレーターは継承されないため、メタクラスは、クラスデコレーターの単一のクラス固有の使用には適さなくなります。Zopeのような大規模なPythonプロジェクトがこれらの野生のゆがみを乗り越えて、クラスデコレーターのようなものをBDFLで勝ち取ったという事実。


PEP-3129を引用していただきありがとうございます。ただし、問題は、クラスデコレータが存在する理由、Guidoがそれらをどう思うか、ZopeまたはIronPythonが出現する前にそれらをどのように使用できたかについてではありません。質問は、今年2016年に、彼らの実用的な使い方について今日ある
Zaur Nasibov

1
右、要点は、元の質問がクラスデコレータのような機能を実装するために使用できるものとしてメタクラスを取り上げていることですが、デコレータの全体的なポイントは、それらが使いやすく、メタクラスよりも明白であるということです。したがって、質問のその部分に対する答えは、「デコレータまたはメタクラスの間で引き裂かれている場合、他の人が理解しやすいので、デコレータを使用する必要があります」です。
quodlibetor

あなたは答える質問を残しています。「...デコレータの全体的なポイントは、それらが使いやすく、メタクラスよりも明白であるということです」-どの場合ですか?次に、「...他の人が理解しやすいので、デコレータを使用する必要があります」本当に?Pythonに長い間依存している間、私はたくさんのメタクラスを見てきました。しかし、クラスデコレータをまったく発見していません。
Zaur Nasibov 2016年

1

このスタックオーバーフローの質問:

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

そうですが、同じSOの質問で正反対が与えられています。メタクラスの方が良いアプローチです。
Zaur Nasibov 2016年

1

クラスのデコレータで行うことができユースケースをお探しすることは無益である- 何もクラスのデコレータで行うことができますメタクラスで行うことができます。登録の例ですら。それを証明するために、デコレータを適用するメタクラスを次に示します。

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
あなたが言うように-デコレーターで何でもできます。問題は、メタクラスではなくクラスデコレータを介して実行する必要があるケースは何ですか。
Zaur Nasibov 2016年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.