具有部分功能的猴子补丁
Monkey patching with a partial function
我正在尝试从导入的包中对 SomeClass
上的方法进行 monkeypatch:
from somepackage import SomeClass
def newmethod(obj, node, **kwargs):
""" """
SomeClass.oldmethod = newmethod
其中 obj
和 node
在 SomeClass.oldmethod
的默认调用签名中:
class SomeClass(object):
def oldmethod(obj, node):
""" """
我知道 monkeypatching 不是一个好的做法,但我们需要一个解决方法来解决一些否则无法解决的问题。上面的方法工作得很好,但我们想使用部分函数来做到这一点。例如:
from functools import partial
newmethod_a = partial(newmethod, foo='a')
newmethod_b = partial(newmethod, foo='b')
正在调用部分函数,因为我们需要传递不同的 **kwargs。但是当我现在尝试超载时:
SomeClass.oldmethod = newmethod_a
我收到一个与传递的参数数量相关的错误,但它非常针对我的问题,因此粘贴它可能没有帮助...我认为该错误与 oldmethod
的调用签名有关采用两个位置参数 (obj, node
),我的偏函数没有正确传递对 obj
和 node
的引用。我尝试过不同的结构,例如:
newmethod_a = partial(SomeClass.newmethod, foo='a')
很抱歉,我无法生成一个最小的工作示例。我希望也许专家会从经验中认识到这个问题,并告诉我我正在尝试的事情是否可能在 partial
.
的范围内
谢谢
这是一个简单的例子:
from functools import partial
class foo(object):
def bar(self, pos1, **kwargs):
print("bar got self=%r, pos1=%r, kwargs=%r" % (self, pos1, kwargs))
foo.bar = partial(foo.bar, qux=1)
baz = foo()
baz.bar(1) # Fails...
这失败了 TypeError
。这样做的原因是 baz.bar
是一个绑定方法,它期望它的第一个参数是 foo
实例,但 partial
对象不是,因此 Python 将当您调用 baz.bar
时,不会为您添加 self
。 (这不完全正确,但真正的原因是相当技术性的。请参阅下面链接的描述符操作方法。)调用 baz.bar(baz, 1)
会起作用。要解决此问题,您必须再次创建 foo.bar
方法:
import types
# In Python 2:
foo.bar = types.MethodType(partial(foo.bar.__func__, qux=1), None, foo)
# Method that is compatible with both Python 2 and 3:
foo.bar = types.MethodType(partial(foo.bar, qux=1), foo)
# Python 3 only:
from functools import partialmethod
foo.bar = partialmethod(foo.bar, qux=1)
baz = foo()
baz.bar(1) # Works!
另请参阅:
- 密切相关:Adding a Method to an Existing Object, functools.partial on class method
松散相关,函数与方法和when/how方法绑定:
- Documentation on Method Objects
- How-To guide for descriptors
- Bind an unbound method
替换:
newmethod_a = functools.partial(newmethod, foo='a')
与:
def newmethod_a(obj, node, **kwargs):
kwargs.update({"foo": "a"})
return newmethod(obj, node, **kwargs)
我正在尝试从导入的包中对 SomeClass
上的方法进行 monkeypatch:
from somepackage import SomeClass
def newmethod(obj, node, **kwargs):
""" """
SomeClass.oldmethod = newmethod
其中 obj
和 node
在 SomeClass.oldmethod
的默认调用签名中:
class SomeClass(object):
def oldmethod(obj, node):
""" """
我知道 monkeypatching 不是一个好的做法,但我们需要一个解决方法来解决一些否则无法解决的问题。上面的方法工作得很好,但我们想使用部分函数来做到这一点。例如:
from functools import partial
newmethod_a = partial(newmethod, foo='a')
newmethod_b = partial(newmethod, foo='b')
正在调用部分函数,因为我们需要传递不同的 **kwargs。但是当我现在尝试超载时:
SomeClass.oldmethod = newmethod_a
我收到一个与传递的参数数量相关的错误,但它非常针对我的问题,因此粘贴它可能没有帮助...我认为该错误与 oldmethod
的调用签名有关采用两个位置参数 (obj, node
),我的偏函数没有正确传递对 obj
和 node
的引用。我尝试过不同的结构,例如:
newmethod_a = partial(SomeClass.newmethod, foo='a')
很抱歉,我无法生成一个最小的工作示例。我希望也许专家会从经验中认识到这个问题,并告诉我我正在尝试的事情是否可能在 partial
.
谢谢
这是一个简单的例子:
from functools import partial
class foo(object):
def bar(self, pos1, **kwargs):
print("bar got self=%r, pos1=%r, kwargs=%r" % (self, pos1, kwargs))
foo.bar = partial(foo.bar, qux=1)
baz = foo()
baz.bar(1) # Fails...
这失败了 TypeError
。这样做的原因是 baz.bar
是一个绑定方法,它期望它的第一个参数是 foo
实例,但 partial
对象不是,因此 Python 将当您调用 baz.bar
时,不会为您添加 self
。 (这不完全正确,但真正的原因是相当技术性的。请参阅下面链接的描述符操作方法。)调用 baz.bar(baz, 1)
会起作用。要解决此问题,您必须再次创建 foo.bar
方法:
import types
# In Python 2:
foo.bar = types.MethodType(partial(foo.bar.__func__, qux=1), None, foo)
# Method that is compatible with both Python 2 and 3:
foo.bar = types.MethodType(partial(foo.bar, qux=1), foo)
# Python 3 only:
from functools import partialmethod
foo.bar = partialmethod(foo.bar, qux=1)
baz = foo()
baz.bar(1) # Works!
另请参阅:
- 密切相关:Adding a Method to an Existing Object, functools.partial on class method
松散相关,函数与方法和when/how方法绑定:
- Documentation on Method Objects
- How-To guide for descriptors
- Bind an unbound method
替换:
newmethod_a = functools.partial(newmethod, foo='a')
与:
def newmethod_a(obj, node, **kwargs):
kwargs.update({"foo": "a"})
return newmethod(obj, node, **kwargs)