4

メソッドをデコレートするとき、それはまだクラスにバインドされていないため、im_class属性はまだありません。デコレータ内のクラスに関する情報を取得する方法を探しています。私はこれを試しました:

import types

def decorator(method):

    def set_signal(self, name, value):
        print name
        if name == 'im_class':
            print "I got the class"

    method.__setattr__ = types.MethodType(set_signal, method)

    return method


class Test(object):
    @decorator
    def bar(self, foo):
        print foo

しかし、それは何も印刷しません。

私はこれを行うことを想像することができます:

class Test(object):
    @decorator(klass=Test)
    def bar(self, foo):
        print foo

しかし、私がそれを避けることができれば、それは私の一日になるでしょう。

4

4 に答える 4

3

__setattr__object.attribute =明示的な割り当てでのみ呼び出されます。クラスの構築では属性の割り当ては使用されませんが、Test.__dict__代わりにディクショナリ()が構築されます。

ただし、クラスにアクセスするには、いくつかの異なるオプションがあります。

  1. 代わりにクラスデコレータを使用してください。ビルド後に完成したクラスが渡されます。クラス内でメソッドを置き換える(装飾する)ことで、そのクラスの個々のメソッドを装飾できます。関数デコレータとクラスデコレータの組み合わせを使用して、どのメソッドをデコレートするかをマークできます。

    def methoddecoratormarker(func):
        func._decorate_me = True
        return func
    
    def realmethoddecorator(func):
        # do something with func. 
        # Note: it is still an unbound function here, not a method!
        return func
    
    def classdecorator(klass):
        for name, item in klass.__dict__.iteritems():
            if getattr(item, '_decorate_me', False):
                klass.__dict__[name] = realmethoddecorator(item)
    

    もちろん、クラスデコレータの代わりにメタクラスを使用して同じことを実現できます。

  2. チートsys._getframe()し、呼び出しフレームからクラスを取得するために使用します。

    import sys
    
    def methoddecorator(func):
         callingframe = sys._getframe(1)
         classname = callingframe.f_code.co_name
    

    取得できるのはクラスの名前だけであることに注意してください。この時点では、クラス自体はまだ構築中です。(マッピング)にアイテムを追加するとcallingframe.f_localsそれらは新しいクラスオブジェクトの一部になります。

  3. selfメソッドが呼び出されるたびにアクセスします。selfは結局のところインスタンスへの参照であり、self.__class__少なくとも、関数が定義された元のクラスのサブクラスになります。

于 2012-10-08T09:57:34.127 に答える
1

私の厳密な答えは次のようになります。デコレータの実行時にクラスがまだ存在しないため、不可能です。

より長い答えはあなたの非常に正確な要件に依存します。私が書いたように、クラスがまだ存在しない場合、クラスにアクセスすることはできません。1つの解決策は、装飾されたメソッドを後で「変換」するようにマークすることです。次に、メタクラスまたはクラスデコレータを使用して、クラスの作成後に変更を適用します。

別のオプションには、いくつかの魔法が含まれます。implementsでメソッドの実装を探しzope.interfacesます。解析されたばかりのクラスに関する情報にアクセスできます。ユースケースに十分かどうかはわかりません。

于 2012-10-08T09:40:23.627 に答える
0

記述子を確認することをお勧めします。これらを使用すると、属性にアクセスするときに使用されるを実装__get__でき、オブジェクトとそのタイプに応じて異なるものを返すことができます。

于 2012-10-08T09:30:17.997 に答える
0

メソッドデコレータを使用して、対象のメソッドにいくつかのマーカー属性を追加し、メソッドを反復処理してマーカー属性を検索し、ロジックを実行するメタクラスを使用します。メタクラスコードはクラスの作成時に実行されるため、新しく作成されたクラスへの参照があります。

class MyMeta(object):
  def __new__(...):
    ...
    cls = ...
    ... iterate over dir(cls), find methods having .is_decorated, act on them
    return cls
def decorator(f):
  f.is_decorated = True
  return f
class MyBase(object):
  __metaclass__ = MyMeta
class MyClass(MyBase):
  @decorator
  def bar(self, foo):
    print foo

MyClassのプログラマーがの使用を忘れていることが心配な場合は、呼び出し元のスタックフレーム()のグローバルディクショナリを調べることMyBaseで、メタクラスを強制的にに設定できます。decoratorsys._getframe()

于 2012-10-08T09:50:45.037 に答える