복붙노트

[PYTHON] 클래스의 모든 메서드를 래핑하는 방법?

PYTHON

클래스의 모든 메서드를 래핑하는 방법?

파이썬에서 특정 클래스의 모든 메서드를 래핑하고 싶습니다. 클래스의 코드를 최소한으로 편집하면됩니다. 이 문제를 어떻게 해결해야합니까?

해결법

  1. ==============================

    1.이를 수행하는 우아한 방법은 Michael Foord의 Voidspace 블로그에 메타 클래스의 개념과 메타 캐일 장식 방법 섹션에서 사용 방법에 대한 항목에 설명되어 있습니다. 약간 간소화하고 상황에 적용하면 다음과 같은 결과가 발생합니다.

    이를 수행하는 우아한 방법은 Michael Foord의 Voidspace 블로그에 메타 클래스의 개념과 메타 캐일 장식 방법 섹션에서 사용 방법에 대한 항목에 설명되어 있습니다. 약간 간소화하고 상황에 적용하면 다음과 같은 결과가 발생합니다.

    from types import FunctionType
    from functools import wraps
    
    def wrapper(method):
        @wraps(method)
        def wrapped(*args, **kwrds):
        #   ... <do something to/with "method" or the result of calling it>
        return wrapped
    
    class MetaClass(type):
        def __new__(meta, classname, bases, classDict):
            newClassDict = {}
            for attributeName, attribute in classDict.items():
                if isinstance(attribute, FunctionType):
                    # replace it with a wrapped version
                    attribute = wrapper(attribute)
                newClassDict[attributeName] = attribute
            return type.__new__(meta, classname, bases, newClassDict)
    
    class MyClass(object):
        __metaclass__ = MetaClass  # wrap all the methods
        def method1(self, ...):
            # ...etc ...
    

    파이썬에서, 함수 / 메소드 데코레이터는 함수 래퍼와 그것들을 쉽고 (그리고 더 예쁘게) 사용하기위한 구문 론적 설탕입니다.

    Python 3 호환성 업데이트

    이전 코드는 Python 3.x에서 사용하기 위해 번역해야 할 Python 2.x 메타 클래스 구문을 사용하지만 이전 버전에서는 더 이상 작동하지 않습니다. 즉, 다음을 사용해야합니다.

    class MyBase(metaclass=MetaClass)
        ...
    

    대신에:

    class MyBase(object): 
        __metaclass__ = MetaClass"
        ...
    

    원하는 경우, Python 2.x와 3.x 모두와 호환되는 코드를 작성할 수 있지만 이렇게하면 원하는 메타 클래스를 상속하는 새로운 기본 클래스를 동적으로 생성하는 약간 더 복잡한 기술을 사용해야하므로 다음과 같은 오류를 피할 수 있습니다. 두 버전의 Python 사이의 구문 차이. 이것은 기본적으로 벤자민 피터슨 (Benjamin Peterson)의 6 모듈의 with_metaclass () 함수가 수행하는 작업입니다.

    from types import FunctionType
    from functools import wraps
    
    def wrapper(method):
        @wraps(method)
        def wrapped(*args, **kwrds):
            print('{!r} executing'.format(method.__name__))
            return method(*args, **kwrds)
        return wrapped
    
    
    class MetaClass(type):
        def __new__(meta, classname, bases, classDict):
            newClassDict = {}
            for attributeName, attribute in classDict.items():
                if isinstance(attribute, FunctionType):
                    # replace it with a wrapped version
                    attribute = wrapper(attribute)
                newClassDict[attributeName] = attribute
            return type.__new__(meta, classname, bases, newClassDict)
    
    
    def with_metaclass(meta):
        """ Create an empty class with the supplied bases and metaclass. """
        return type.__new__(meta, "TempBaseClass", (object,), {})
    
    
    if __name__ == '__main__':
    
        # Inherit metaclass from a dynamically-created base class.
        class MyClass(with_metaclass(MetaClass)):
            @staticmethod
            def a_static_method():
                pass
    
            @classmethod
            def a_class_method(cls):
                pass
    
            def a_method(self):
                pass
    
        instance = MyClass()
        instance.a_static_method()  # Not decorated.
        instance.a_class_method()   # Not decorated.
        instance.a_method()         # -> 'a_method' executing
    
  2. ==============================

    2.당신은 프로그래밍 방식으로 클래스의 메서드에 래퍼를 설정한다는 것을 의미합니까 ?? 음, 이것은 아마도 매우 나쁜 습관이지만, 다음과 같이 할 수 있습니다.

    당신은 프로그래밍 방식으로 클래스의 메서드에 래퍼를 설정한다는 것을 의미합니까 ?? 음, 이것은 아마도 매우 나쁜 습관이지만, 다음과 같이 할 수 있습니다.

    def wrap_methods( cls, wrapper ):
        for key, value in cls.__dict__.items( ):
            if hasattr( value, '__call__' ):
                setattr( cls, key, wrapper( value ) )
    

    예를 들어 수업을 가지고 있다면

    class Test( ):
        def fire( self ):
            return True
        def fire2( self ):
            return True
    

    및 래퍼

    def wrapper( fn ):
        def result( *args, **kwargs ):
            print 'TEST'
            return fn( *args, **kwargs )
        return result
    

    다음 전화

    wrap_methods( Test, wrapper )
    

    Test 클래스에 정의 된 모든 메서드에 래퍼를 적용합니다. 주의해서 사용하십시오! 사실, 그것을 전혀 사용하지 마십시오!

  3. ==============================

    3.기본 클래스 동작을 광범위하게 수정해야하는 경우 MetaClass가 필요합니다. 대체 접근법이 있습니다.

    기본 클래스 동작을 광범위하게 수정해야하는 경우 MetaClass가 필요합니다. 대체 접근법이 있습니다.

    유스 케이스가 클래스의 인스턴스 메소드를 래핑하는 것으로 제한되는 경우 __getattribute__ 마법 메소드를 무시할 수 있습니다.

    from functools import wraps
    def wrapper(func):
        @wraps(func)
        def wrapped(*args, **kwargs):
            print "Inside Wrapper. calling method %s now..."%(func.__name__)
            return func(*args, **kwargs)
        return wrapped
    

    래퍼를 생성하는 동안 functools.wraps를 사용하십시오. 래퍼가 현명한 TraceBacks를 제공하기 때문에 디버깅을위한 것이라면 더욱 그렇습니다.

    import types
    class MyClass(object): # works only for new-style classes
        def method1(self):
            return "Inside method1"
        def __getattribute__(self, name):
            attr = super(MyClass, self).__getattribute__(name)
            if type(attr) == types.MethodType:
                attr = wrapper(attr)
            return attr
    
  4. ==============================

    4.파이썬 장식자를 사용하는 것은 이것을하는 가장 청결한 방법입니다. 디버그를하거나 최소한 나타나는 코드를 추적하는 것처럼 보입니다.

    파이썬 장식자를 사용하는 것은 이것을하는 가장 청결한 방법입니다. 디버그를하거나 최소한 나타나는 코드를 추적하는 것처럼 보입니다.

  5. from https://stackoverflow.com/questions/11349183/how-to-wrap-every-method-of-a-class by cc-by-sa and MIT license