Определение множество методов запроса HTTP в классе, используя partialmethods


Я использую объект, который ожидает в качестве аргумента ключевого слова для каждого вызова, но я не собираюсь его менять. В этом случае время ожидания 10. Что является лучшим способом, чтобы добавить partialmethods для каждого атрибута.

В моем примере я хочу установить тайм-аут на мои просьбы сессии HTTP-методов.

Я мог monkeypatch сессии.запрос с partialmethod. Это работает довольно хорошо, потому что все методы сессии идут по запросу. Session().post на самом деле переживает Session.request('post', <inputs>).

from requests import Session

Session.request = partialmethod(Session.request, timeout=10)

Однако то, что о случаях использования там, где существует не один способ я могу это исправить или я просто не хочу делать что-то потенциально опасное, как monkeypatching.

У меня есть помощник сессии объект, который настраивает auth и адаптер (здесь не приводится) для клиента, но я хочу разные таймауты по умолчанию для различных методов. Я даже не могу monkeypatch метод в этом случае.

Я мог бы сделать это после стандартного определения класса в цикле.

from functools import partialmethod
from requests import Session

class SeshTester:
    def __init__(self):
        self.s = Session()

    def request(self, method, *args, **kwargs):
        return self.s.request(method, *args, **kwargs)


for r_method in ['delete', 'get', 'head', 'options']:
    setattr(SeshTester, r_method, partialmethod(SeshTester.request, r_method, timeout=7))

for r_method in ['connect', 'put', 'push']:
    setattr(SeshTester, r_method, partialmethod(SeshTester.request, r_method, timeout=13))

# this call is equivalent to self.s.request('get', 'http://google.com', timeout=7
print(SeshTester().get('http://google.com'))

Я не думаю, что это очень разборчивой, но не знают, как это сделать внутри стандартное определение класса. SeshTester объект, очевидно, не ссылка-в состоянии, прежде чем она состоит, но я не хочу повторяться, делая post = partialmethod(request, 'post', timeout=13) для каждого возможного метода HTTP.

Я хотел бы проанализировать этот цикл в классе, но не знаю, как ссылаться на объект, прежде чем он полностью определен.



Комментарии
1 ответ

Можно конечно делать то, что было изложено, что лежит вне определения класса внутри класса определение себя через использование localsи с той целью, что можно делать, может быть выражено более четко, с меньшей избыточностью кода и подстановки, используя setattr.

class SeshTester:
def __init__(self):
self.s = Session()

def request(self, method, *args, **kwargs):
return self.s.request(method, *args, **kwargs)

for r_method in ['delete', 'get', 'head', 'options']:
locals()[r_method] = partialmethod(request, r_method, timeout=7)

for r_method in ['connect', 'put', 'push']:
locals()[r_method] = partialmethod(request, r_method, timeout=13)

Увидев это работает, как задумано из оболочки:

>>> SeshTester().get
functools.partial(<bound method SeshTester.request of <__main__.SeshTester object at 0x7fde00176ef0>>, 'get', timeout=7)
>>> SeshTester().put
functools.partial(<bound method SeshTester.request of <__main__.SeshTester object at 0x7fddf8da0668>>, 'put', timeout=13)

Еще одна вещь: документацию по ссылке выше на самом деле не описать, что реализуется, по крайней мере, с CPython; в других реализациях может быть locals() ведут себя по-разному внутри класса Сфера, однако в настоящее время усилия в стандартизации этого представляются недостаточно определенными поведение с CPython реализации в Пеп-558, такая, что код, приведенный выше пример будет работать, как положено по стандарту (если Пеп получает ратифицировала в Python 3.7).


Однако, как было упомянуто в вопрос, если API обеспечивает стандартизированный вспомогательный метод, который обеспечивает определенный Session экземпляр, конечно, он может обеспечить подкласса Session экземпляр с конкретной функции/методы, которые требуют переопределения быть применены в случае необходимости. Рассмотрим следующие:

class SessionExtras(Session):

def request(self, method, url, *a, **kw):
default_timeout = 7
timeouts = {
'CONNECT': 13,
'PUT': 13,
'PUSH': 13,
}
if kw.get('timeout') is None:
kw['timeout'] = timeouts.get(method, default_timeout)
return super().request(method, url, *a, **kw)

Возможно, таким образом намерение как быть выражен в гораздо более ясной форме, и позволяют API пользователям воспользоваться настоящим Session экземпляр, а не какой-то суррогат. В этом примере default_timeout и timeouts определяется в функции определения, однако они могли бы быть перемещены в классе или даже модуль уровня, в зависимости от предполагаемого использования и, как это должно быть настроены для конкретного API, который пишется.

2
ответ дан 3 февраля 2018 в 03:02 Источник Поделиться