2017-02-16 1 views
3

클래스를 호출 할 때 사용되는 매개 변수 중 하나를 사용하여 클래스의 클래스 메서드에 대해 몇 가지 유효성 검사를 수행하려고합니다.데코 레이팅 된 클래스의 상속 된 클래스 메서드에서 cls 동작

이렇게하려면 필자는 필요한 메서드에 데코레이터를 적용 할 클래스에 데코레이터를 사용하는데,이 데코레이터는 함수의 매개 변수 중 하나를 사용하여 유효성 검사 함수를 수행합니다.

이 모든 것이 기본 클래스에서 잘 작동합니다 (이 예제에서는 Parent이라고합니다).

그러나 Parent을 상속하는 다른 클래스를 만들면 (이 예제에서는 Child이라고합니다) 상속 된 데코레이션 클래스 메서드는 더 이상 정상적으로 작동하지 않습니다.

Child 클래스의 클래스 메서드 내에있는 cls 매개 변수는 Child이 아니지만 대신 Parent입니다.

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

내 질문

은 다음과 같습니다 : 다음과 같은 결과가 발생합니다 다음 예

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') 

촬영

Child의 classmethod 같이 Parent으로 호출되는 이유는 무엇

  • cl
  • 이 디자인을 사용하여 원하는 동작을 얻을 수 있습니까?

P. : 파이썬 2.7.10과 파이썬 3.5.2 모두에서이 기능을 시도했으며 동일한 동작을했습니다.

답변

5

바인딩 된 클래스 메서드을 꾸미고 있습니다. 이 객체는 Parent을 유지하고 호출 될 때 원래의 shout 함수로 전달됩니다. wrapper() 메서드에서 어떤 cls이 바인딩되는지는 전달되지 않고 무시됩니다.

포장을 벗긴의 classmethods 첫째, 당신은 __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

관련 문제