如何在不更改基础 class 的情况下向 class 的实例添加行为
How can i add behaviour to a instance of a class without changing the base class
我从我的代码中的第三方库中获取了 class 的实例
i = x.get_instance()
然后我的代码从这个实例调用一个方法。
i.method_a()
这将在我想添加行为的 class 中调用一个方法。
我现在找到的唯一方法是
class BetterClass(ThirdPartyClass):
def getMessage(self):
message = super(BetterClass, self).getMessage()
... add behaviour
return message
i.__class__ = BetterClass
i.method_a()
但是添加这种行为的更好方法是什么,因为我无法更改返回的实例。
我自己没有初始化
您可以使用:
>>> class Example(object):
... def foo(self):
... print "foo"
...
>>> a=Example()
>>> a.foo()
foo
>>>
>>> def new_foo(self):
... Example.foo(self)
... print "new"
...
>>> funcType = type(Example.foo)
>>> a.foo = funcType(new_foo, a, Example)
>>> a.foo()
foo
new
这里,type
就是class。 funcType
是一个实例方法:
>>> funcType
<type 'instancemethod'>
>>> help(funcType)
...
class instancemethod(object)
| instancemethod(function, instance, class)
|
| Create an instance method object.
...
另外,(感谢@bruno desthuilliers),你可以这样做:
a.foo = new_foo.__get__(a, type(a))
而不是使用 funcType
。
如果您确定 x.get_instance()
将 return 是 ThirdPartyClass
的一个实例,您可以使用 monkeypatch ThirdPartyClass
:
from thirdpartlib.module import ThirdPartyClass
def patch_ThirdPartyClass():
_get_message = ThirdPartyClass.get_message
def get_message(self):
message = _get_message()
# add behaviour here
return message
ThirdPartyClass.get_message = get_message
patch_ThirdPartyClass()
你只是想确保这段代码在每个进程中只执行一次 - 如果你不确定你能保证这一点,你最好添加一些标志:
def patch_ThirdPartyClass():
_get_message = ThirdPartyClass.get_message
if getattr(_get_message, "patched", False):
return
def get_message(self):
message = _get_message()
# add behaviour here
return message
get_message.patched = True
ThirdPartyClass.get_message = get_message
patch_ThirdPartyClass()
您还想确保这段代码在 在 对 x.get_instance()
的任何调用之前执行,显然。
如果出于任何原因您不能使用上述解决方案,您仍然可以在每个实例的基础上对方法进行 monkeypatch:
def patch_instance(instance):
_get_message = instance.get_message
def get_message(self):
message = _get_message()
# add behaviour here
return message
instance.get_message = get_message.__get__(instance, type(instance))
return instance
i = patch_instance(x.get_instance())
同样的考虑适用于/确保你只应用这个补丁一次,所以你可能想要添加一个类似的标志内容并测试 class monkeypatch 版本。
最后一点:如果您必须回退到 patch_instance
解决方案并希望确保 all 调用 x.get_instance()
return 打补丁的实例,您可能还想打补丁 x.get_instance
以便它调用 patch_instance
.
假设你有一个 class Foo 有一个 bar 方法:
>>> class Foo(object):
... def __init__(self, name):
... self.name = name
... def bar(self):
... print "bar", self.name
如果您创建此 class 的实例,名为 foo
...
>>> foo = Foo('eggs')
>>> foo.bar()
bar eggs
...那么你想要修补 bar 方法。先定义一个函数:
>>> def bar(self):
... self.__class__.bar(self) # you can call the original method
... print "spam", self.name
您可以在不猴子修补 class:
的情况下修补实例
>>> import types
>>> foo.bar = types.MethodType(bar, foo, Foo)
>>> foo.bar()
bar eggs
spam eggs
不确定这是否正确(可能不是一个好主意)但它有效。
原文class完好:
>>> otherfoo = Foo('foo')
>>> otherfoo.bar()
bar foo
我从我的代码中的第三方库中获取了 class 的实例
i = x.get_instance()
然后我的代码从这个实例调用一个方法。
i.method_a()
这将在我想添加行为的 class 中调用一个方法。
我现在找到的唯一方法是
class BetterClass(ThirdPartyClass):
def getMessage(self):
message = super(BetterClass, self).getMessage()
... add behaviour
return message
i.__class__ = BetterClass
i.method_a()
但是添加这种行为的更好方法是什么,因为我无法更改返回的实例。 我自己没有初始化
您可以使用:
>>> class Example(object):
... def foo(self):
... print "foo"
...
>>> a=Example()
>>> a.foo()
foo
>>>
>>> def new_foo(self):
... Example.foo(self)
... print "new"
...
>>> funcType = type(Example.foo)
>>> a.foo = funcType(new_foo, a, Example)
>>> a.foo()
foo
new
这里,type
就是class。 funcType
是一个实例方法:
>>> funcType
<type 'instancemethod'>
>>> help(funcType)
...
class instancemethod(object)
| instancemethod(function, instance, class)
|
| Create an instance method object.
...
另外,(感谢@bruno desthuilliers),你可以这样做:
a.foo = new_foo.__get__(a, type(a))
而不是使用 funcType
。
如果您确定 x.get_instance()
将 return 是 ThirdPartyClass
的一个实例,您可以使用 monkeypatch ThirdPartyClass
:
from thirdpartlib.module import ThirdPartyClass
def patch_ThirdPartyClass():
_get_message = ThirdPartyClass.get_message
def get_message(self):
message = _get_message()
# add behaviour here
return message
ThirdPartyClass.get_message = get_message
patch_ThirdPartyClass()
你只是想确保这段代码在每个进程中只执行一次 - 如果你不确定你能保证这一点,你最好添加一些标志:
def patch_ThirdPartyClass():
_get_message = ThirdPartyClass.get_message
if getattr(_get_message, "patched", False):
return
def get_message(self):
message = _get_message()
# add behaviour here
return message
get_message.patched = True
ThirdPartyClass.get_message = get_message
patch_ThirdPartyClass()
您还想确保这段代码在 在 对 x.get_instance()
的任何调用之前执行,显然。
如果出于任何原因您不能使用上述解决方案,您仍然可以在每个实例的基础上对方法进行 monkeypatch:
def patch_instance(instance):
_get_message = instance.get_message
def get_message(self):
message = _get_message()
# add behaviour here
return message
instance.get_message = get_message.__get__(instance, type(instance))
return instance
i = patch_instance(x.get_instance())
同样的考虑适用于/确保你只应用这个补丁一次,所以你可能想要添加一个类似的标志内容并测试 class monkeypatch 版本。
最后一点:如果您必须回退到 patch_instance
解决方案并希望确保 all 调用 x.get_instance()
return 打补丁的实例,您可能还想打补丁 x.get_instance
以便它调用 patch_instance
.
假设你有一个 class Foo 有一个 bar 方法:
>>> class Foo(object):
... def __init__(self, name):
... self.name = name
... def bar(self):
... print "bar", self.name
如果您创建此 class 的实例,名为 foo
...
>>> foo = Foo('eggs')
>>> foo.bar()
bar eggs
...那么你想要修补 bar 方法。先定义一个函数:
>>> def bar(self):
... self.__class__.bar(self) # you can call the original method
... print "spam", self.name
您可以在不猴子修补 class:
的情况下修补实例>>> import types
>>> foo.bar = types.MethodType(bar, foo, Foo)
>>> foo.bar()
bar eggs
spam eggs
不确定这是否正确(可能不是一个好主意)但它有效。
原文class完好:
>>> otherfoo = Foo('foo')
>>> otherfoo.bar()
bar foo