开发者

Monkey patch __del__ to new function

For specific debugging purposes I'd li开发者_运维知识库ke to wrap the del function of an arbitrary object to perform extra tasks like write the last value of the object to a file.

Ideally I want to write monkey(x) and it should mean that the final value of x is printed when x is deleted

Now I figured that del is a class method. So the following is a start:

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

However if I want to monkey specific objects only I suppose I need to dynamically rewrite their class to a new one?! Moreover I need to do this anyway, since I cannot access del of built-in types?

Anyone knows how to implement that?


While special 'double underscore' methods like __del__, __str__, __repr__, etc. can be monkey-patched on the instance level, they'll just be ignored, unless they are called directly (e.g., if you take Omnifarious's answer: del a won't print a thing, but a.__del__() would).

If you still want to monkey patch a single instance a of class A at runtime, the solution is to dynamically create a class A1 which is derived from A, and then change a's class to the newly-created A1. Yes, this is possible, and a will behave as if nothing has changed - except that now it includes your monkey patched method.

Here's a solution based on a generic function I wrote for another question: 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


del a deletes the name 'a' from the namespace, but not the object referenced by that name. See this:

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

Also, some_object.__del__ is not guaranteed to be called at all.

Also, I already answered your question here (in german).


You can also inherit from some base class and override the __del__ method (then only thing you would need would be to override class when constructing an object). Or you can use super built-in method.


Edit: This won't actually work, and I'm leaving it here largely as a warning to others.

You can monkey patch an individual object. self will not get passed to functions that you monkey patch in this way, but that's easily remedied with functools.partial.

Example:

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

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜