2017-02-16 6 views
3

私は、クラスを呼び出すときに使用されたパラメータの1つを使用して、クラスのクラスメソッドのバリデーションをいくつか試行しています。デコレーションされたクラスの継承されたクラスメソッドにおける動作clone

これを行うには、必要なメソッドにデコレータを適用するクラスのデコレータを使用しています。デコレータは、関数内のパラメータの1つを使用して検証関数を実行します。

これはすべて基本クラス(この例ではParentと呼ぶ)でうまくいきます。

しかし、Parentを継承する別のクラス(この例ではChildと呼ぶ)を作成すると、継承した装飾クラスメソッドは正常に動作しなくなります。

Childクラスのクラスメソッド内のclsパラメータは、Childではなく、代わりにParentです。

import inspect 


def is_number(word): 
    if word.isdigit(): 
     print('Validation passed') 
    else: 
     raise Exception('Validation failed') 


class ClassDecorator(object): 

    def __init__(self, *args): 
     self.validators = args 

    def __decorateMethod(self): 
     def wrapped(method): 
      def wrapper(cls, word, *args, **kwargs): 
       for validator in self.validators: 
        validator(word) 
       return method(word, *args, **kwargs) 
      return wrapper 
     return wrapped 

    def __call__(self, cls): 
     for name, method in inspect.getmembers(cls): 
      if name == 'shout': 
       decoratedMethod = self.__decorateMethod()(method) 
       setattr(cls, name, classmethod(decoratedMethod)) 
     return cls 


@ClassDecorator(is_number) 
class Parent(object): 

    @classmethod 
    def shout(cls, word): 
     print('{} is shouting {}'.format(cls, word)) 

    @classmethod 
    def say(cls): 
     print('{} is talking'.format(cls)) 


class Child(Parent): 
    pass 


Parent.shout('123') 
Child.shout('321') 

は、次のような出力になります次の例を取ると

Validation passed 
<class '__main__.Parent'> is shouting 123 
Validation passed 
<class '__main__.Parent'> is shouting 321 

私の質問は以下のとおりです。ChildためのクラスメソッドがParentなどで呼び出さないのはなぜ

  • cl
  • このデザインを使用して、望ましい動作を得ることは可能ですか?

P.S.:私はあなたがバインドクラスメソッドを飾っているのPython 2.7.10とPython 3.5.2の両方でこれを試してみたと同じ動作

答えて

5

を得ています。 Parentを保持し、呼び出されたときに元のshout関数に渡すのはこのオブジェクトです。あなたのwrapper()メソッドで束縛されているclsは渡されず、無視されます。

アンラップのクラスメソッドは、まず、あなたは__func__属性で基本となる関数オブジェクトを取得することができます

def __call__(self, cls): 
    for name, method in inspect.getmembers(cls): 
     if name == 'shout': 
      decoratedMethod = self.__decorateMethod()(method.__func__) 
      setattr(cls, name, classmethod(decoratedMethod)) 
    return cls 

あなたは今、あなたのラッパーがあまりにも結合していない機能を処理していることを考慮し、そうで渡す必要がありますcls引数または手動バインド:

# pass in cls explicitly: 
return method(cls, word, *args, **kwargs) 

# or bind the descriptor manually: 
return method.__get__(cls)(word, *args, **kwargs) 
+0

これは機能しました。助けてくれてありがとう – Oct

関連する問題