14

次のことを行うクラスデコレータを作成する最良の方法を見つけようとしています:

  1. 装飾されたクラスにいくつかの関数を挿入します
  2. 装飾されたクラス__init__が呼び出された後に、これらの関数のいずれかを強制的に呼び出します

現在、「元の」メソッドへの参照を保存して、元のメソッドと追加の関数を呼び出す__init__my に置き換えています。__init__これは次のようになります。

orig_init = cls.__init__

def new_init(self, *args, **kwargs):
    """
    'Extend' wrapped class' __init__ so we can attach to all signals
    automatically
    """

    orig_init(self, *args, **kwargs)
    self._debugSignals()

cls.__init__ = new_init

__init__オリジナルを「増強」するか、別の場所に呼び出しを挿入するより良い方法はありますか? 本当に必要なのはself._debugSignals()、オブジェクトが作成された後に my が呼び出されることだけです。また、それが自動的に行われるようにしたいので、アフター__init__が良い場所だと思いました。

余分な雑用。デコレータノート

このデコレーターの背景について言及する価値があるかもしれません。完全なコードはここにあります。デコレーターのポイントは、PyQt シグナルに自動的にアタッチし、それらが発行されたときに出力することです。の独自のサブクラスをデコレートすると、デコレータは正常に動作QtCore.QObjectしますが、最近、すべての QObject の子を自動的にデコレートしようとしています。

アプリケーションで「デバッグ」モードを使用して、すべての信号を自動的に出力して、期待どおりに動作していることを確認したいと思います。これにより大量のデバッグが発生すると確信していますが、何が起こっているのかを確認したいと思います。

問題は、私の現在のバージョンのデコレーターが、置き換え時にセグメンテーション違反QtCore.QObject.__init__を引き起こしていることです。これをデバッグしようとしましたが、コードはすべて SIP で生成されたものであり、あまり経験がありません。

__init__そのため、関数呼び出しの後に関数呼び出しを挿入し、できればセグメンテーション違反を回避するための、より安全でより Pythonic な方法があるかどうか疑問に思っていました。

4

3 に答える 3

15

この投稿この回答に基づいて、これを行う別の方法は、カスタムメタクラスを使用することです。これは次のように機能します (Python 2.7 でテスト済み)。

# define a new metaclass which overrides the "__call__" function
class NewInitCaller(type):
    def __call__(cls, *args, **kwargs):
        """Called when you call MyNewClass() """
        obj = type.__call__(cls, *args, **kwargs)
        obj.new_init()
        return obj


# then create a new class with the __metaclass__ set as our custom metaclass
class MyNewClass(object):
    __metaclass__ = NewInitCaller
    def __init__(self):
        print "Init class"
    def new_init(self):
        print "New init!!"

# when you create an instance
a = MyNewClass()
>>> Init class
>>> New init!!

基本的な考え方は次のとおりです。

  1. 呼び出すMyNewClass()と、メタクラスを検索し、定義したことがわかりますNewInitCaller

  2. メタクラス __call__関数が呼び出されます。

  3. この関数は、MyNewClassを使用してインスタンスを作成しますtype

  4. インスタンスは独自に実行されます__init__(「Init クラス」を出力します)。

  5. new_initその後、メタ クラスはインスタンスの関数を呼び出します。

于 2013-07-05T20:37:32.097 に答える