简体   繁体   English

如何扩展Class实例

[英]How to extend Class instance

MyClass is defined in module.py . MyClassmodule.py定义。 There is no way we can modify it. 我们无法修改它。 But we do know the Class definition looks like this: 但我们知道Class定义如下所示:

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

I start my script with importing the module and then declaring an object's instance: 我通过导入模块然后声明一个对象的实例来启动我的脚本:

import module    
foo = module.MyClass()

Then I write my own function: 然后我写自己的功能:

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

Now, every time foo.method('') is used I want to call function() so it prints the same message too. 现在,每次使用foo.method('')我都想调用function()所以它也打印相同的消息。

Would this situation be referred as the monkey patching ? 这种情况会被称为monkey patching吗? How to achieve what is needed? 如何实现所需?

Yes, it's called monkey-patching. 是的,它被称为猴子修补。

This is basically decoration, but done manually after the class is already defined. 这基本上是装饰,但是在已经定义了类之后手动完成。

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)

It will affect all instances of MyClass , even those that were created before the patch was applied. 它将影响MyClass所有实例,甚至是那些在应用补丁之前创建的实例。

If you don't need to dynamically modify runtime behaviour, avoid monkey-patching and prefer to use inheritance to customise behaviour, as suggested in the comments. 如果您不需要动态修改运行时行为,请避免使用猴子修补,并且更喜欢使用继承来自定义行为,如注释中所示。 It's less hacky. 它不那么黑客。

You could subclass it as well: 你也可以将它子类化:

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)

And use it like: 并使用它像:

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

Or, if you want to make your class a "new-style" class (for Python 2 - judging by your print statements) - just have MyClass inherit from object and then you can user super : 或者,如果你想让你的类成为一个“新风格”类(对于Python 2 - 通过你的print语句判断) - 只需让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

This is an alternative to wim's answer that also involves monkey-patching. 这是wim的答案的替代方案,也涉及猴子修补。 However, it does it through functionality provided by unittest.mock . 但是,它通过unittest.mock提供的功能来实现。 The advantage of this approach is that a context manager is used to automatically apply and remove the patch within a limited scope: 这种方法的优点是上下文管理器用于在有限的范围内自动应用和删除补丁:

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')

Output 产量

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

Ended up with this solution till there is better one posted... 结束这个解决方案,直到有更好的发布...

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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM