2014-07-23 1 views
3

나는 그것에 원숭이와 일치하는 일부 바보 같은 코드가 있습니다. 아래의 예는 생산을 목적으로하지 않는 자습을위한 것입니다.Monkeypatching : 함수에 클래스에 메서드를 대체

class MyClass: 

    def some_method(self): 
     print("some_method call") 
     self.yet_another_method() 

    def yet_another_method(self): 
     print('yet_another_method call') 


def some_function(self): 
    print("some function call") 
    self.yet_another_method() 

obj = MyClass() 
obj.some_method() 
obj.some_method = some_function 
obj.some_method() 

나는 다음과 같은 오류가이 코드를 실행하면 :

TypeError: non_class_some_method() missing 1 required positional argument: 'self' 

그것은 파이썬 인터프리터는 암시 적으로 some_functionobj을 통과 할 수 있음을 분명합니다. 그러나 인트로 스펙 션을 수행하고 바이트 코드를 가져올 때 메소드의 유사한 표현 (대체 전후)이 있습니다.

import dis 
import inspect 


class MyClass: 

    def some_method(self): 
     print("some_method call") 
     self.yet_another_method() 

    def yet_another_method(self): 
     print('yet_another_method call') 


def some_function(self): 
    print("some function call") 
    self.yet_another_method() 

obj = MyClass() 
dis.dis(obj.some_method) 
print(inspect.getargspec(obj.some_method)) 
obj.some_method = some_function 
print("======================================================================") 
dis.dis(obj.some_method) 
print(inspect.getargspec(obj.some_method)) 

그 결과이 방법을 왜 일어나는지

8   0 LOAD_GLOBAL    0 (print) 
       3 LOAD_CONST    1 ('some_method call') 
       6 CALL_FUNCTION   1 (1 positional, 0 keyword pair) 
       9 POP_TOP    

    9   10 LOAD_FAST    0 (self) 
      13 LOAD_ATTR    1 (yet_another_method) 
      16 CALL_FUNCTION   0 (0 positional, 0 keyword pair) 
      19 POP_TOP    
      20 LOAD_CONST    0 (None) 
      23 RETURN_VALUE   
ArgSpec(args=['self'], varargs=None, keywords=None, defaults=None) 
====================================================================== 
16   0 LOAD_GLOBAL    0 (print) 
       3 LOAD_CONST    1 ('some function call') 
       6 CALL_FUNCTION   1 (1 positional, 0 keyword pair) 
       9 POP_TOP    

17   10 LOAD_FAST    0 (self) 
      13 LOAD_ATTR    1 (yet_another_method) 
      16 CALL_FUNCTION   0 (0 positional, 0 keyword pair) 
      19 POP_TOP    
      20 LOAD_CONST    0 (None) 
      23 RETURN_VALUE   
ArgSpec(args=['self'], varargs=None, keywords=None, defaults=None) 

사람이 설명 할 수주십시오?

+0

인스턴스에 정의 된 함수는 바인딩 된 메서드로 변환되지 않으므로 class 특성으로 정의해야합니다 (또는 ['types.MethodType'] (https://docs.python.org/2)를 사용할 수 있습니다. /library/types.html#types.MethodType) 인스턴스를 사용하여 메소드로 함수를 등록하십시오.) –

+0

클래스의 모든 인스턴스가 아닌 클래스의 인스턴스 하나에 대해서만 메소드를 변경하려면 질문에 응답해야합니다 여기 : http://stackoverflow.com/questions/972/adding-a-method-to-an-existing-object?rq=1 –

답변

3

대부분의 대답은 https://wiki.python.org/moin/FromFunctionToMethod입니다.

항상
  • def 수율
  • method이 래퍼 만 생성됩니다
  • 단지 함수, 클래스 및 인스턴스 주위에 얇은 호출 가능 래퍼 인 function 객체 기능 : 짧은 긴 이야기를 만들려면 클래스의 속성입니다. 인스턴스의 속성 일 때가 아닙니다.

코드를 작동 시키려면 (인스턴스 단위로 monkeypatching) 함수, 클래스 및 인스턴스에서 method을 생성하는 메커니즘을 수동으로 호출해야합니다. 새로운 스타일의 클래스를 사용하는 경우 가장 간단한 해결책은 즉, 직접 기능에 대한 설명 프로토콜을 호출하는 것입니다 : 이전 스타일 클래스를 사용하는 경우

obj.some_method = some_function.__get__(obj, type(obj)) 

당신이 당신의 예에서처럼 (그리고 이는 좋은 생각) 대신 types.MethodType을 사용할 수 있지만 일부 기존 코드가 붙어 있지 않으면 클래스를 새로운 스타일로 만드는 것이 더 좋습니다 (=> 상속 from object).

관련 문제