猴子补丁 __del__ 为新函数

10 投票
4 回答
1495 浏览
提问于 2025-04-16 17:40

为了特定的调试目的,我想要对一个对象的del函数进行包装,这样可以执行一些额外的任务,比如把这个对象的最后一个值写入文件。

理想情况下,我希望能写 monkey(x) 这样,当我删除x的时候,x的最终值就会被打印出来。

现在我发现del是一个类的方法。所以我现在的思路是这样的:

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

但是如果我只想对特定的对象进行这种处理,我想我需要动态地把它们的类改成一个新的类?而且我必须这样做,因为我无法访问内置类型的del方法,对吗?

有没有人知道怎么实现这个?

4 个回答

0

你还可以从某个基础类继承,并重写 __del__ 方法(这样你只需要在创建对象的时候重写这个类就可以了)。或者你也可以使用内置的 super 方法。

1

del a 这个命令是用来删除名字 'a',也就是说,它把 'a' 这个名字从命名空间中去掉了,但它并不会删除 'a' 所指向的那个对象。你可以这样理解:

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

另外,some_object.__del__ 并不一定会被调用

还有,我之前在 这里(用德语)回答过你的问题。

8

一些特殊的“双下划线”方法,比如 __del____str____repr__ 等,虽然可以在实例级别进行修改,但如果不直接调用它们,它们就会被忽略。举个例子,如果你执行 del a,是不会有任何输出的,但如果你直接调用 a.__del__(),就会有反应。

如果你还是想在运行时修改某个类 A 的单个实例 a,可以通过动态创建一个新类 A1,这个新类是从 A 继承而来的,然后把 a 的类改成新创建的 A1。是的,这样做是可行的,a 的表现就像什么都没变一样,只不过现在它包含了你修改过的方法。

下面是一个基于我为另一个问题写的通用函数的解决方案:Python 方法解析之谜

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

撰写回答