2017-01-27 21 views
3

MyClass определен в module.py. Мы не можем изменить его. Но мы знаем, что определение класса выглядит следующим образом:Как продлить экземпляр класса

class MyClass: 
    def method(self, msg): 
     print 'from method:', msg 

Я начинаю свой скрипт с импортом модуля, а затем объявить экземпляр объекта:

import module  
foo = module.MyClass() 

Тогда я написать свою собственную функцию:

def function(msg): 
    print 'from function:', msg 

Теперь, каждый раз, когда используется foo.method(''), я хочу позвонить function(), поэтому он печатает одно и то же сообщение.

Будет ли эта ситуация называться monkey patching? Как достичь того, что необходимо?

+1

Подкласс его и переопределить метод '()' и вызовите базовый класс 'method()', используя 'super()'. –

+2

Есть ли причина, по которой вы не просто создаете подкласс? –

+0

Извините, я забыл упомянуть, что я не могу подкласса или наследовать от 'MyClass'. – alphanumeric

ответ

3

Да, это называется обезьяна-латание.

Это в основном оформление, но выполняется вручную после того, как класс уже определен.

from functools import wraps 

def wrapper(f): 
    @wraps(f) 
    def wrapped(*args, **kwargs): 
     myFunction() 
     return f(*args, **kwargs) 
    return wrapped 

MyClass.printThis = wrapper(MyClass.printThis) 

Это затронет все экземпляры MyClass, даже те, которые были созданы до применения патча.

Если вам не нужно, чтобы динамически изменять поведение во время выполнения, избежать обезьяны заплат и предпочитают использовать наследование настроить поведение, как это было предложено в комментариях. Это менее хаки.

-1

Законченное с этим решением, пока там лучше один отвечал ...

class MyClass: 
    def method(self, msg): 
     print 'from method:', msg 

def function(msg, callback): 
    print 'from function:', msg 
    callback(msg) 

foo = MyClass() 
foo.function = function 
foo.function(msg='message', callback=foo.method) 
+3

Как вызывается вызов функции '(') 'every time'()'? –

+0

Здесь '' метод() ', который вызывается через' callback' каждый раз, когда вызывается 'function'. – alphanumeric

1

Вы могли бы подкласс, а также:

class MyClass: 
    def method(self, msg): 
     print 'from method:', msg 

def function(msg): 
    print 'from function:', msg 

class MyNewClass(MyClass): 
    def method(self, msg): 
     function(msg) 
     MyClass.method(self, msg) 

И использовать его как:

>>> a = MyNewClass() 
>>> a.method("test") 
from function: test 
from method: test 

Или, если вы хотите, чтобы ваш класс «новый стиль» класс (для Python 2 - судя по вашим высказываниям печати) - просто MyClass наследуют от object, а затем вы можете пользователь super:

class MyClass(object): # object added here 
    def method(self, msg): 
     print 'from method:', msg 

def function(msg): 
    print 'from function:', msg 

class MyNewClass(MyClass): 
    def method(self, msg): 
     function(msg) 
     super(self.__class__, self).method(msg) # super added here 
+0

Я бы назвал это с помощью 'super (MyNewClass, self) .method (msg)' не уверен, что он будет работать с вашей схемой вызова (метод не является методом класса) – boatcoder

+0

@boatcoder super не работает (в Python2), если только класс является новым классом стиля (пример OP не является и является py2 на основе отпечатков). Добавлен пример, если они хотят приспособиться к новому стилю :) – NikT

+0

Хорошо поймать этот класс старого стиля, я этого даже не заметил. – boatcoder

1

Это альтернатива wim's answer, которая также включает в себя обезглавливание обезьян. Тем не менее, он выполняет функции, предоставляемые unittest.mock. Преимущество этого подхода состоит в том, что менеджер контекста используется для автоматического применения и удалить патч в пределах ограниченного объема:

from unittest import mock 

# This class would be defined in some third-party library 
class MyClass: 
    def method(self, msg): 
     print('from method:', msg) 


def function(msg): 
    print('from function:', msg) 


old_method = MyClass.method 


def new_method(self, msg): 
    old_method(self, msg) 
    function(msg) 


# The patch is only applied within this scope 
with mock.patch.object(MyClass, 'method', new_method): 
    foo = MyClass() 
    foo.method('message with patched') 

# By this point MyClass is "back to normal" 
print('---') 
foo.method('message with original') 

Выходной

from method: message with patched 
from function: message with patched 
--- 
from method: message with original 

 Смежные вопросы

  • Нет связанных вопросов^_^