将Python方法动态绑定到实例可以正确绑定方法名称,但不能绑定方法
我正在为一组RESTful服务编写一个客户端。给定参数,REST调用的主体具有相同的XML结构。有几十个电话,我不会全部执行。因此,我希望使它们易于指定和使用。REST方法在单独的模块中按功能分组,需要共享相同的urllib2 opener以进行身份验证和cookie。下面是一个如何声明方法的示例:将Python方法动态绑定到实例可以正确绑定方法名称,但不能绑定方法,python,types,Python,Types,我正在为一组RESTful服务编写一个客户端。给定参数,REST调用的主体具有相同的XML结构。有几十个电话,我不会全部执行。因此,我希望使它们易于指定和使用。REST方法在单独的模块中按功能分组,需要共享相同的urllib2 opener以进行身份验证和cookie。下面是一个如何声明方法的示例: @rest_method('POST', '/document') def createDocument(id, title, body): # possibly some validati
@rest_method('POST', '/document')
def createDocument(id, title, body):
# possibly some validation on the arguments
pass
开发人员需要关心的就是验证。XML(用于POST和PUT)或URL(用于GET和DELETE)的格式以及响应的反序列化在帮助器方法中完成。修饰后的方法收集在客户机对象中,从中执行和处理这些方法。例如:
c = RESTClient('http://foo.com', username, password)
c.createDocument(1, 'title', 'body')
代码完成了。唯一的问题是将修饰的方法附加到客户机类。虽然所有修饰的方法都可以在客户机实例中看到,但它们都共享相同的定义,即最后一个要绑定的方法。下面是一个简单的例子,它复制了我看到的行为:
import types
class C(object): pass
def one(a): return a
def two(a, b): return a+b
def bracketit(t): return '(%s)' % t
c = C()
for m in (one, two):
new_method = lambda self, *args, **kwargs:\
bracketit(m(*args, **kwargs))
method = types.MethodType(new_method, c, C)
setattr(C, m.__name__, method)
print c.one
print c.two
print c.two(1, 2)
print c.one(1)
运行此操作时,我得到以下输出:
<bound method C.<lambda> of <__main__.C object at 0x1003b0d90>>
<bound method C.<lambda> of <__main__.C object at 0x1003b0d90>>
(3)
Traceback (most recent call last):
File "/tmp/test.py", line 19, in <module>
print c.one(1)
File "/tmp/test.py", line 12, in <lambda>
bracketit(m(*args, **kwargs))
TypeError: two() takes exactly 2 arguments (1 given)
(3)
回溯(最近一次呼叫最后一次):
文件“/tmp/test.py”,第19行,在
打印c.1(1)
文件“/tmp/test.py”,第12行,在
括号(m(*args,**kwargs))
TypeError:two()正好接受2个参数(给定1个)
我不知道为什么这两个方法是以相同的方式绑定的。我还没有找到多少关于instancemethod如何将方法绑定到实例的文档。引擎盖下面发生了什么,我如何修复上述代码,以便第二次调用打印“(1)”?lambda正在调用
m
,将其从本地范围中拉出。for循环结束后,m
设置为two
。调用c.one
或c.two
将导致调用two
通过查看回溯的最后一行,可以看出正在调用two
:
TypeError: two() takes exactly 2 arguments (1 given)
这应该符合您的期望,但有点混乱:
class C(object): pass
def one(a): return a
def two(a, b): return a+b
def bracketit(t): return '(%s)' % t
c = C()
for m in (one, two):
def build_method(m):
return (lambda self, *args, **kwargs:
bracketit(m(*args, **kwargs)))
method = build_method(m)
setattr(C, m.__name__, method)
print c.one
print c.two
print c.two(1, 2)
print c.one(1)
我还删除了未绑定方法的显式创建,因为它是不必要的。问题是变量
m
在循环结束时被保留为two
,这会影响循环期间所做的定义。您可以通过使用嵌套函数创建闭包来修复它:
for m in (one, two):
def make_method(m):
def new_method(self, *args, **kwargs):
return bracketit(m(*args, **kwargs))
return new_method
method = types.MethodType(make_method(m), c, C)
setattr(C, m.__name__, method)
在测试代码中运行时,会生成:
<bound method C.new_method of <__main__.C object at 0x0135EF30>>
<bound method C.new_method of <__main__.C object at 0x0135EF30>>
(3)
(1)
(3)
(1)