1

簡単にアクセスしたり、統合したりできるように、あらゆるタイプのクラスを装飾するデコレーターを作成し、それらすべてに標準インターフェースを追加することに成功しました...

私はメタクラスの使用に抵抗してきました。この点に関する文献では、メタクラスは過剰であり、ほとんどの場合、クラス デコレータに置き換えることができると書かれています。私を悩ませているのは次のとおりです。

def Decorator(somearg):

    def wrapper(cls):
        clsinit = cls.__init__
        cls.members = []

        def __init__(self, *args, **kwargs):
            #do something with somearg...
            self.__class__.members.append(self)
            clsinit(self,*args,**kwargs)

        cls.__init__ = clsinit
        return cls

    return wrapper

@Decorator('thearg')
class A(object):
    pass

a = A()
b = A()

Python デバッガーを使用すると、インポート時にクラス A が引数 'thearg' ですぐに装飾されます。しかし、A() をインスタンス化するたびに、インスタンスはデコレーターで定義された init を直接呼び出し、前のレイヤーを通過しません。クラスが各メンバーを記録し、新しいインスタンスがインスタンス化されるたびにリセットされないようにしたいので、これは素晴らしいことです。しかし、その理由を理解しているかどうかはわかりません。

この特定のケースで、誰かが python インタープリターの物理を説明できますか?

4

3 に答える 3

2

クラスを変更するだけで新しいクラスを作成しない場合は、ラッパー関数(ラッパークラスである必要があります)は必要ありません。

def Decorator(cls):
    clsinit = cls.__init__
    cls.members = []

    def __init__(self, *args, **kwargs):
        clsinit(self, *args, **kwargs)
        self.__class__.members.append(self)

    cls.__init__ = __init__
    return cls

ところで、基本クラスを作成してそこから継承する必要があります。

class Base(object):
    members = []
    def __init__(self):
        self.__class__.members.append(self)

class A(Base):
    pass

はるかにきれい

于 2013-02-09T04:01:05.560 に答える
0

回答をありがとう@JBernardoと@martineau。このコードの目的は、インスタンスに簡単に到達できるように、クラスオブジェクトのコンテナのような動作を実装することでした。ただし、すべてが同じ継承クラスにあるわけではなく、各クラスに関連するインスタンスに一度に1つずつアクセスしたいと思います。

実際にコードに再度取り組むことで、私の問題を理解することができました。

a)デコレータはその引数someargで呼び出されます

b)次の行の内容(クラスAの定義)がラッパー関数の引数として使用されます。この関数の内部I:1)無限再帰を回避するために最初のクラスinitを覚えておく2)インスタンスレベルで変更を加えるために新しいinitを定義する3)クラスの新しいinitメソッドをバインドする4)変換されたクラスオブジェクトを返す

c)returnはクラスオブジェクトであるため、インスタンスをインスタンス化するたびに、これが新しいクラスでバインドされた方法であるため、initに直接移動します。

于 2013-02-09T10:02:39.373 に答える
0

OK、更新された質問の修正されたコードを参照して、次のように尋ねます。

「しかし、A() をインスタンス化するたびに、インスタンスは、前のレイヤーを通過せずに、デコレータで定義された init を直接呼び出します。」

これは、関数wrapper()によって作成されたクラス デコレータ関数Decorator()が に適用されるときに、を独自の動的に定義された関数class Aに置き換えるためです。その関数は、s がインスタンス化されるたびに呼び出されるものであり、最初にいくつかのことを行い、最後にオリジナルを呼び出すように記述されています。A__init__()wrapper.__init__()AA.__init__()

于 2013-02-09T04:33:40.453 に答える