0

装飾されたクラスに属性を追加するまでは、魔法のように機能するデコレーターを実装しました。クラスをインスタンス化すると、calss 属性にアクセスできません。次の最小限の作業例を取り上げます。

from module import specialfunction

class NumericalMathFunctionDecorator:
    def __init__(self, enableCache=True):
        self.enableCache = enableCache

    def __call__(self, wrapper):
        def numericalmathfunction(*args, **kwargs):
            func = specialfunction(wrapper(*args, **kwargs))
            """
            Do some setup to func with decorator arguments (e.g. enableCache)
            """
        return numericalmathfunction

@NumericalMathFunctionDecorator(enableCache=True)
class Wrapper:
    places = ['home', 'office']
    configs = {
               'home':
                  {
                   'attr1': 'path/at/home',
                   'attr2': 'jhdlt'
                  },
               'office':
                  {
                   'attr1': 'path/at/office',
                   'attr2': 'sfgqs'
                  }
              }
    def __init__(self, where='home'):
        # Look for setup configuration on 'Wrapper.configs[where]'.
        assert where in Wrapper.places, "Only valid places are {}".format(Wrapper.places)
        self.__dict__.update(Wrapper.configs[where])

    def __call__(self, X):
        """Do stuff with X and return the result
        """
        return X ** 2

model = Wrapper()

Wrapper クラス (#1) をインスタンス化すると、次のエラーが発生します。

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-5-a99bd3d544a3> in <module>()
     15         assert where in Wrapper.places, "Only valid places are {}".format(Wrapper.places)
     16 
---> 17 model = Wrapper()

<ipython-input-5-a99bd3d544a3> in numericalmathfunction(*args, **kwargs)
      5     def __call__(self, wrapper):
      6         def numericalmathfunction(*args, **kwargs):
----> 7             func = wrapper(*args, **kwargs)
      8         return numericalmathfunction
      9 

<ipython-input-5-a99bd3d544a3> in __init__(self, where)
     13     def __init__(self, where='home'):
     14         # Look for setup configuration on 'Wrapper.configs[where]'.
---> 15         assert where in Wrapper.places, "Only valid places are {}".format(Wrapper.places)
     16 
     17 model = Wrapper()

AttributeError: 'function' object has no attribute 'places'

デコレータを使用すると、Wrapper はその属性へのアクセスを失う関数になると思います...

これを解決する方法のアイデアはありますか? たぶん回避策があります

4

1 に答える 1

1

Wrapper(クラスであった)をnumericalmathfunction関数オブジェクトに置き換えました。そのオブジェクトにはクラス属性がありません。

本質的に、デコレータはこれを行います:

class Wrapper:
    # ...

Wrapper = NumericalMathFunctionDecorator(enableCache=True)(Wrapper)

そのため、NumericalMathFunctionDecorator.__call__メソッドが返すものはすべて、クラスを置き換えました。へのすべての参照はWrapper、その戻り値を参照するようになりました。メソッドで名前を使用するとWrapper__init__元のクラスではなく、そのグローバルを参照しています。

を使用して現在のクラスにアクセスすることも、type(self)これらの属性を参照することもできますself(名前のルックアップがクラスに渡されます)。

def __init__(self, where='home'):
    # Look for setup configuration on 'Wrapper.configs[where]'.
    assert where in self.places, "Only valid places are {}".format(self.places)
    self.__dict__.update(self.configs[where])

また

def __init__(self, where='home'):
    # Look for setup configuration on 'Wrapper.configs[where]'.
    cls = type(self)
    assert where in cls.places, "Only valid places are {}".format(cls.places)
    self.__dict__.update(cls.configs[where])

どちらの場合も、サブクラスを実行したことがある場合は、サブクラスの属性を参照することになりますWrapper(デコレータ クロージャからクラスを釣り上げる必要があるため、この場合は実行できません)。

または、元のクラスを返された関数の属性として保存することもできます。

def __call__(self, wrapper):
    def numericalmathfunction(*args, **kwargs):
        func = specialfunction(wrapper(*args, **kwargs))
        """
        Do some setup to func with decorator arguments (e.g. enableCache)
        """
    numericalmathfunction.__wrapped__ = wrapper
    return numericalmathfunction

次に、その参照を次のように使用します__init__

def __init__(self, where='home'):
    # Look for setup configuration on 'Wrapper.configs[where]'.
    cls = Wrapper
    while hasattr(cls, '__wrapped__'):
        # remove any decorator layers to get to the original
        cls = cls.__wrapped__
    assert where in cls.places, "Only valid places are {}".format(cls.places)
    self.__dict__.update(cls.configs[where])
于 2015-06-08T14:28:33.097 に答える