Динамическое связывание методов Python с экземпляром правильно связывает имена методов, но не метод
Я пишу клиент для группы служб RESTful. Тело вызовов REST имеет одинаковую структуру XML с заданными параметрами. Есть несколько десятков звонков, и я не буду реализовывать их все. Поэтому я хочу, чтобы их было легко задавать и использовать. Методы REST сгруппированы по функциональности в отдельных модулях и должны будут использовать один и тот же инструмент открытия urllib2 для аутентификации и файлов cookie. Вот пример того, как метод объявлен:
@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)
Я не уверен, почему эти два метода связаны одинаково. Я не смог найти много документации о том, как метод instance привязывает методы к экземплярам. Что происходит под капотом, и как мне исправить вышеприведенный код, чтобы второй вызов выводил «(1)»?