2017-02-16 22 views
3

Я пытаюсь сделать некоторые проверки для методов класса класса, используя один из параметров, используемых при их вызове.поведение cls в унаследованном классе метод декорированного класса

Для этого я использую декоратор для класса, который применит декоратор к требуемым методам, который будет выполнять функцию проверки с использованием одного из параметров в функции.

Все это хорошо работает для базового класса (для этого примера я назову его Parent).

Однако, если я создаю еще один класс, который наследует Parent, (для этого примера я назову его Child), унаследованный декорированный класс методов больше не ведет себя нормально.

Параметр cls внутри Метод класса для Child класса не 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, как cls
  • Возможно ли использование этого дизайна для получения желаемого поведения?

P.S.: Я попытался это как на Python 2.7.10 и Python 3.5.2 и получил такое же поведение

ответ

5

Вы украшаете метод связанного класса; этот объект удерживается на Parent и передает его в исходную функцию shout при вызове; независимо от того, cls связан с вашим wrapper(), метод не передается и игнорируется.

UnWrap методы класса первых, вы можете добраться до базового объекта функции с атрибутом __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