2016-10-28 3 views
0

Чтобы написать много HTTP-запросов сухим способом, я хотел бы определить несколько подклассов requests сеансов и наследовать их при необходимости. Я попробовал следующее:Использование super() для наследования нескольких сеансов в запросах Python

import requests, time 

requestbin_URL = 'http://requestb.in/1nsaz9y1'  # For testing only; remains usable for 48 hours 
auth_token = 'asdlfjkwoieur182932385'    # Fake authorization token 

class AuthorizedSession(requests.Session): 
    def __init__(self, auth_token): 
     super().__init__() 
     self.auth_token = auth_token 
     self.headers.update({'Authorization': 'token=' + self.auth_token}) 

class JSONSession(requests.Session): 
    def __init__(self): 
     super().__init__() 
     self.headers.update({'content-type': 'application/json'}) 

class DebugSession(requests.Session): 
    def __init__(self, verify=False): 
     super().__init__() 
     self.verify = verify 

class AuthorizedJSONDebugSession(AuthorizedSession, JSONSession, DebugSession): 
    def __init__(self, auth_token, verify=False): 
     super().__init__(auth_token, verify=verify) 

with AuthorizedJSONDebugSession() as s: 
    response = s.post(requestbin_URL, data={"key" : "value"}) 

Однако, если я пытаюсь запустить этот (в Python 3), я получаю

In [9]: exec(open('requestbin_test_python3.py').read()) 
--------------------------------------------------------------------------- 
TypeError         Traceback (most recent call last) 
<ipython-input-9-cc670860ddd1> in <module>() 
----> 1 exec(open('requestbin_test_python3.py').read()) 

<string> in <module>() 

TypeError: __init__() missing 1 required positional argument: 'auth_token' 

То, что я надеялся, что super().__init__ применительно к AuthorizedJSONDebugSession будет «достаточно умный», чтобы понять, что auth_token используется для инициализации AuthorizedSession и verify для инициализации DebugSession. (Аналогичный пример, используя только AuthorizedSession и JSONSession сделал произведение).

Однако, похоже, это не так. Как я могу изменить этот код, чтобы он работал?

+2

Вы можете использовать kwargs всюду, чтобы дать каждому суперклассу необходимый ему параметр, но я бы избавился от множественного наследования все вместе. Обычно он превращается в неприятный источник ошибок. – solarc

+2

Множественное наследование сложнее в лучшем случае, и лучше всего использовать «один базовый класс + пару миксинов». –

ответ

1

Стандартный способ борьбы с этим только позволяют параметры ключевых слов и сделать все классы принимают **kwargs:

import requests, time 

requestbin_URL = 'http://requestb.in/1nsaz9y1'  # For testing only; remains usable for 48 hours 
auth_token = 'asdlfjkwoieur182932385'    # Fake authorization token 

class AuthorizedSession(requests.Session): 
    def __init__(self, **kwargs): 
     try: 
      self.auth_token = kwargs.pop('auth_token') 
     except KeyError: 
      raise TypeError('Missing auth_token parameter!') 

     super().__init__(**kwargs) 
     self.headers.update({'Authorization': 'token=' + self.auth_token}) 

class JSONSession(requests.Session): 
    def __init__(self, **kwargs): 
     super().__init__(**kwargs) 
     self.headers.update({'content-type': 'application/json'}) 

class DebugSession(requests.Session): 
    def __init__(self, **kwargs): 
     self.verify = kwargs.pop('verify', False) 
     super().__init__(**kwargs) 

class AuthorizedJSONDebugSession(AuthorizedSession, JSONSession, DebugSession): 
    def __init__(self, **kwargs): 
     super().__init__(**kwargs) 

with AuthorizedJSONDebugSession() as s: 
    response = s.post(requestbin_URL, data={"key" : "value"}) 

Метод dict.pop выглядит для данного ключа и удаляет его из словаря. Второй аргумент - значение по умолчанию для использования, если не указано KeyError.

Обратите внимание, что это важно, что всякий раз, когда вы определяете __init__ в подклассе вы звоните super().__init__(**kwargs), даже если вы думаете, что в этом случае не требуется. Поскольку добавление подкласса в иерархию классов с несколькими предками может изменить mro и, не выполняя этот вызов, может закончиться сломанной инициализацией.

+0

Чтобы избежать «Отсутствующего параметра auth_token» TypeError, мне пришлось инициализировать 'AuthorizedJSONDebugSession' как' AuthorizedJSONDebugSession (auth_token = auth_token) '. –

+0

@KurtPeek Ну, если вы хотите указать значение по умолчанию, которое вы также можете сделать: 'self.auth_token = kwargs.pop ('auth_token', auth_token)', так что он примет значение глобальной переменной, если параметр не является прошло. – Bakuriu

1

Я в большом сомнении такой подход будет работать в общем случае, но вы можете попытаться вызвать необходимые __init__ методы в явном виде:

import requests, time 

requestbin_URL = 'http://requestb.in/1nsaz9y1'  # For testing only; remains usable for 48 hours 
auth_token = 'asdlfjkwoieur182932385'    # Fake authorization token 

class AuthorizedSession(requests.Session): 
    def __init__(self, auth_token): 
     super().__init__() 
     self.auth_token = auth_token 
     self.headers.update({'Authorization': 'token=' + self.auth_token}) 

class JSONSession(requests.Session): 
    def __init__(self): 
     super().__init__() 
     self.headers.update({'content-type': 'application/json'}) 

class DebugSession(requests.Session): 
    def __init__(self, verify=False): 
     super().__init__() 
     self.verify = verify 

class AuthorizedJSONDebugSession(AuthorizedSession, JSONSession, DebugSession): 
    def __init__(self, auth_token, verify=False): 
     AuthorizedSession.__init__(self, auth_token) 
     JSONSessions.__init__(self) 
     DebugSession.__init__(self, verify=verify) 

with AuthorizedJSONDebugSession(auth_token) as s: 
    response = s.post(requestbin_URL, data={"key" : "value"}) 
+1

Нет отличной идеи ИМХО. Если вы не можете заставить 'super' работать во множественном наследовании, это обычно сильный запах дизайна. –

+0

@brunodesthuilliers Согласовано – agg3l

1

Взгляните на этот

class AuthorizedJSONDebugSession(AuthorizedSession, JSONSession, DebugSession): 
    def __init__(self, auth_token, verify=False): 
     super().__init__(auth_token, verify=verify) 

with AuthorizedJSONDebugSession() as s: 
    response = s.post(requestbin_URL, data={"key" : "value"}) 

Ваша проблема is with AuthorizedJSONDebugSession() Вы не предоставляете никаких аргументов, но для метода init требуется 1 аргумент маркера auth. def __init__(self, auth_token, verify=False)

Это в основном то же самое, как пытаться сделать следующее:

>>> x=10 
>>> def foo(x): 
...  return x + 1 
... 
>>> foo() 
TypeError: foo() missing 1 required positional argument: 'x' 

В рамках этой функции, x не то же самое, как глобальный x

Чтобы исправить это сделать:

with AuthorizedJSONDebugSession(auth_token) as s: 
    response = s.post(requestbin_URL, data={"key" : "value"}) 

в качестве альтернативы, вы могли изменить I nit для этого, но я бы не рекомендовал его.

def __init__(self, auth_token=auth_token, verify=False)

Вы также должны быть осторожны в том, как вы используете super() передать аргументы. В этом отношении есть и другие проблемы с вашим кодом. Вы должны убедиться, что каждый класс в MRO сотрудничает с тем, что вы хотите сделать, и передает аргументы суперклассам.

Вы также должны быть знакомы с работой P, которая отличается от других языков.

Смежные вопросы