Как я могу дополнить метод объекта Python? - PullRequest
4 голосов
/ 22 ноября 2010

У меня есть список объектов Spam:

class Spam:
    def update(self):
        print('updating spam!')

некоторые из них могут быть объектами SpamLite:

class SpamLite(Spam):
    def update(self):
        print('this spam is lite!')
        Spam.update(self)

Я хотел бы иметь возможность взять произвольный объект изсписок и добавить что-то в его метод обновления, что-то вроде:

def poison(spam):
    tmp = spam.update 
    def newUpdate(self):
        print 'this spam has been poisoned!'
        tmp(self)
    spam.update = newUpdate

Я хочу, чтобы spam.update () теперь печатал:

this spam has been poisoned!
updating spam!

или

this spam has been poisoned!
this spam is lite!
updating spam!

в зависимости от того, был ли это SpamLite или просто спам.

Но это не сработает, потому что spam.update () не передаст аргумент self автоматически, и потому что если tmp покидает область действия или изменяется, он не будет вызывать старое обновление.Есть ли способ, которым я могу сделать это?

Ответы [ 4 ]

4 голосов
/ 22 ноября 2010
def poison(spam):
    tmp = spam.update
    def newUpdate():
        print 'this spam has been poisoned!'
        tmp()
    spam.update = newUpdate

Полный скрипт:

class Spam:
    def update(self):
        print('updating spam!')

class SpamLite(Spam):
    def update(self):
        print('this spam is lite!')
        Spam.update(self)

def poison(spam):
    tmp = spam.update # it is a bound method that doesn't take any arguments
    def newUpdate():
        print 'this spam has been poisoned!'
        tmp()
    spam.update = newUpdate


from operator import methodcaller    
L = [Spam(), SpamLite()]
map(methodcaller('update'), L)
map(poison, L)
print "*"*79
map(methodcaller('update'), L)

Выход:

updating spam!
this spam is lite!
updating spam!
*******************************************************************************
this spam has been poisoned!
updating spam!
this spam has been poisoned!
this spam is lite!
updating spam!
3 голосов
/ 22 ноября 2010

Другой подход, с MethodType :

class Spam:
    def update(self):
        print('updating spam!')

class SpamLite(Spam):
    def update(self):
        print('this spam is lite!')
        Spam.update(self)

def poison(spam):
    import types
    tmp = spam.update 
    def newUpdate(self):
        print 'this spam has been poisoned!'
        tmp()
    newUpdate = types.MethodType(newUpdate, spam, Spam)
    spam.update = newUpdate

spam = Spam()
spam_lite = SpamLite()
poison(spam)
poison(spam_lite)
spam.update()
print
spam_lite.update()
0 голосов
/ 22 ноября 2010

Используйте декораторы, как это:

def method_decorator(f):
    def wrapper(self, *args, **kwargs):
        print('this spam has been poisoned!')
        return f(self)
    return wrapper

class Spam:
    def update(self):
        print('updating spam!')

    @method_decorator
    def update2(self):
        print('updating spam!')

Spam().update()
Spam().update2()

Это печатает:

updating spam!
this spam has been poisoned!
updating spam!

Если вы хотите узнать больше о декораторах, прочитайте это: http://www.drdobbs.com/web-development/184406073

Выше не декоратор "хорошего гражданина", прочитайте статью, чтобы узнать, как ее написать. Обязательно проверьте также библиотеку декораторов: http://pypi.python.org/pypi/decorator

НТН

0 голосов
/ 22 ноября 2010

MonkeyPatching не одобряется в мире питонов.

Вы действительно должны использовать подход Mixin и использовать множественное наследование.

Затем вы можете динамически заменять (обновлять) родителей для достиженияжелаемый эффект.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...