1. ホーム
  2. python

[解決済み] メタクラスの(具体的な)使用例とは?

2022-05-11 11:42:47

質問

メタクラスを好んで使う友人がいて、定期的に解決策を提示しています。

私は、メタクラスを使用する必要はほとんどないと考えています。なぜかというと、クラスにそのようなことをするのであれば、おそらくオブジェクトにするべきだと考えるからです。そして、小さな再設計/リファクタリングが必要です。

メタクラスを使えるようになったことで、多くの場所で多くの人がクラスをある種の二流のオブジェクトとして使うようになり、それは私には悲惨に思えます。プログラミングは、メタプログラミングに取って代わられるのでしょうか?クラスデコレーターの追加により、残念ながらさらに受け入れられやすくなっています。

だから、私はPythonでメタクラスのためのあなたの有効な(具体的な)ユースケースを知るために必死になっています。あるいは、なぜクラスを変異させることが、時々、オブジェクトを変異させるよりも良いのかについて、啓発されたいのです。

私は始めます。

時々、サードパーティの サードパーティライブラリを使用する場合、特定の方法で が便利なことがあります。

(このケースしか思いつきませんし、具体的ではありません)

どのように解決するのですか?

Matplotlibのフロントエンドとして、非対話的なプロットを処理するクラスがあります。 しかし、時折、対話的なプロットを行いたいと思うことがあります。 いくつかの関数で、図形の数を増やしたり、手動で描画を呼び出したりできることがわかりましたが、描画を呼び出すたびにその前後でこれらを行う必要がありました。 そこで、インタラクティブな描画ラッパーとオフスクリーン描画ラッパーの両方を作成するために、次のようなことをするよりも、適切なメソッドをラップしたメタクラスを介してこれを行う方がより効率的であることがわかりました。

class PlottingInteractive:
    add_slice = wrap_pylab_newplot(add_slice)

この方法は、APIの変更などに対応できませんが、クラス属性を反復するものは __init__ にあるクラス属性を再セットするものの方が効率的で、最新の状態を保つことができます。

class _Interactify(type):
    def __init__(cls, name, bases, d):
        super(_Interactify, cls).__init__(name, bases, d)
        for base in bases:
            for attrname in dir(base):
                if attrname in d: continue # If overridden, don't reset
                attr = getattr(cls, attrname)
                if type(attr) == types.MethodType:
                    if attrname.startswith("add_"):
                        setattr(cls, attrname, wrap_pylab_newplot(attr))
                    elif attrname.startswith("set_"):
                        setattr(cls, attrname, wrap_pylab_show(attr))

もちろん、もっと良い方法があるかもしれませんが、私はこれが効果的であると感じています。 もちろん、これは __new__ または __init__ などがありますが、これが一番わかりやすい解決策でした。