Патч обезьяны __del__ для новой функции - PullRequest
10 голосов
/ 15 мая 2011

Для конкретных целей отладки я хотел бы обернуть функцию del произвольного объекта для выполнения дополнительных задач, таких как запись последнего значения объекта в файл.

В идеале я хочу написать обезьяны (х) и это должно означать, что окончательное значение 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 ]

7 голосов
/ 15 мая 2011

Хотя специальные методы 'двойного подчеркивания', такие как __del__, __str__, __repr__ и т. Д., Могут быть исправлены обезьянами на уровне экземпляра, они будут просто игнорироваться, если только они не вызваны напрямую (например, если вы примете ответ Omnifarious: 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
0 голосов
/ 15 мая 2011

del a удаляет имя 'a' из пространства имен, но не объект, на который ссылается это имя. Смотрите это:

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

Кроме того, some_object.__del__ не гарантированно вызывается вообще .

Также я уже ответил на ваш вопрос здесь (на немецком языке).

0 голосов
/ 15 мая 2011

Вы можете обезьянить патч для отдельного объекта.self не будет передано функциям, которые вы исправляете таким образом, но это легко исправить с помощью functools.partial.

Пример:

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

def monkey_object(x):
    x.__del__ = functools.partial(p, x)
0 голосов
/ 15 мая 2011

Вы также можете наследовать от некоторого базового класса и переопределить метод __del__ (тогда единственное, что вам нужно, это переопределить класс при создании объекта). Или вы можете использовать super встроенный метод.

...