2011-05-15 2 views
9

특정 디버깅 목적으로 임의의 개체에 대해 del 함수를 사용하여 개체의 마지막 값을 파일에 쓰는 등의 추가 작업을 수행하고 싶습니다. 지금은 클래스의 방법이라고 생각Monkey patch __del__ to new function

이상적으로 나는 원숭이 (x)의 을 쓰고 싶어 그리고 X는

를 삭제 될 때 x의 최종 값이 인쇄되는 것을 의미한다. 난 단지 내가 동적으로 새로운 자신의 클래스를 다시 작성해야한다고 가정 원숭이 특정 개체에하려는 경우

class Test: 
    def __str__(self): 
     return "Test" 

def p(self): 
    print(str(self)) 

def monkey(x): 
    x.__class__.__del__=p 

a=Test() 
monkey(a) 
del a 

! : 그래서 다음은 시작이다 또한 내장 유형에 액세스 할 수 없으므로 어쨌든이 작업을 수행해야합니까?

누구든지 구현 방법을 알고 있습니까?

답변

6

동안 특별한 '이중 밑줄'방법 __del__, __str__, __repr__ 등 원숭이 패치 인스턴스 레벨에있을 수있는 것처럼, 그들은 그냥 무시됩니다 을 직접 (예 : 무언가를 가져 가면 del a은 아무 것도 출력하지 않지만 a.__del__()은 대답 할 것입니다.)

여전히 런타임에 클래스 Aa이 솔루션은 동적으로 A에서 파생 된 클래스 A1를 작성하는 것입니다 단일 인스턴스를 패치 한 후 새로 생성에 a의 클래스를 변경 원숭이합니다

A1. 예, 가능하며 a은 아무 것도 변경되지 않은 것처럼 행동합니다. 단, 원숭이 패치 방법이 포함되어 있습니다. Python method resolution mystery

def override(p, methods): 
    oldType = type(p) 
    newType = type(oldType.__name__ + "_Override", (oldType,), methods) 
    p.__class__ = newType 


class Test(object): 
    def __str__(self): 
     return "Test" 

def p(self): 
    print(str(self)) 

def monkey(x): 
    override(x, {"__del__": p}) 

a=Test() 
b=Test() 
monkey(a) 
print "Deleting a:" 
del a 
print "Deleting b:" 
del b 
+2

이 접근법의 두 가지 문제점 : '__class__'를 다시 할당 할 수 없기 때문에 int 나 list와 같은 힙 유형에서는 작동하지 않습니다. 둘째, 유형 검사는 대상이 원숭이인지 아닌지에 따라 결과가 달라집니다. 그러면 매우 혼란스러운 오류가 발생할 수 있습니다. – pillmuncher

+0

__class__에 할당 할 수 있습니까? 와우, 그건 단지 ... 와우. – drxzcl

+1

위의 내 의견에는 오타가 있습니다. '힙이 아닌 형식'을 읽어야합니다. – pillmuncher

0

일부 기본 클래스에서 상속 받고 __del__ 메서드를 재정의 할 수도 있습니다 (객체를 구성 할 때 클래스를 재정의하는 것이 필요합니다). super 기본 제공 방법을 사용할 수 있습니다.

+0

이 트릭은 일부 임시 디버깅을위한 것이므로 실제 기본 클래스를 정의하지는 않을 것입니다.또한 __del__ 함수를 사용하여 파생 클래스에서 super 호출을 기억해야합니다. 그리고 마침내 이것은 빌트인을 위해 작동하지 않을 것입니다. 나는 원숭이에게 정상적인리스트를 줄 수있는 방법이 있기를 바란다. – Gerenuk

+0

http://stackoverflow.com/questions/192649/can-you-monkey-patch-methods-on-core-types-in-python - 여기에 대한 두 번째 대답은 훌륭한 설명입니다 –

0

개별 개체를 원숭이 패치 할 수 있습니다. self은 원숭이 패치와 같은 방식으로 전달되지 않지만 functools.partial으로 쉽게 해결할 수 있습니다.

예 : 그들은이라고하지 않는

def monkey_class(x): 
    x.__class__.__del__ = p 

def monkey_object(x): 
    x.__del__ = functools.partial(p, x) 
+0

시도해 보셨습니까? 내가 실수를 한 것은 확실하지 않지만 분명히 x .__ del__은 효과가 없다. 델이 엄격하게 클래스 메소드이기 때문에 아마? 어쨌든 나는 그것을 얻을 수 없다 :(그리고 나는 .partial이 가비지 수집되지 않도록 x에 대한 참조를 유지한다는 느낌을 받는다? – Gerenuk

+0

특별한 메소드는 dict 클래스에서만 호출되기 때문에 작동하지 않는다. 솔루션은 '일반적인'방법으로 만 작동합니다. –

+0

@Boaz Yaniv : 매일 새로운 것을 배울 수 있습니다.이 답변을 다른 사람들에게 경고로 남겨 두었습니다 :-) – Omnifarious

0

del a는 이름 그 이름에 의해 참조 'A'네임 스페이스 있지만에서 개체를 삭제합니다

는 여기에 내가 또 다른 질문에 대한 쓴 일반적인 기능을 기반으로하는 솔루션입니다. 이 참조 : 또한

>>> x = 7 
>>> y = x 
>>> del x 
>>> print y 
7 

, some_object.__del__is not guaranteed to be called at all을.

또한 고객님의 질문에 이미 here (독일어)으로 대답했습니다.