2009-11-27 35 views
3

我正在为一组RESTful服务编写客户端。给定参数,REST调用的主体具有相同的XML结构。有几十个电话,我不会执行所有的电话。因此,我想让他们易于指定和易于使用。 REST方法按功能分组到不同的模块中,并且需要共享相同的urllib2开启器来进行认证和cookie。下面是如何声明一种方法的示例:将Python方法动态绑定到实例正确绑定方法名称,但不是方法

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

我不知道为什么这两种方法的结合一样的方法。我一直无法找到关于instancemethod如何将方法绑定到实例的很多文档。发生了什么事情,以及如何修复上述代码,以便第二次调用打印“(1)”?

回答

3

该lambda呼吁m,拉它从本地范围。 for循环结束后,m设置为two。调用c.onec.two将导致调用two

你可以告诉two正在看着你回溯的最后一行称为:

TypeError: two() takes exactly 2 arguments (1 given) 

A good demonstration of what is going on can be found here.

这应该做你所期望的,但它是一个有点凌乱:

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) 

我也删除了未绑定方法的显式创建,因为它是非常规的。

+0

卫生署。当然。谢谢。 –

3

问题是变量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)