I want to share requests
session among multiple class instances and also be able to reset the session for all such instances.
So I have the disconnect
method for resetting the session for all instances:
import requests
class CachedSession:
def __init__(self):
self._initialized = None
def __get__(self, *args, **kwargs):
if self._initialized is None:
self._initialized = self.connect()
return self._initialized
def connect(self):
session = requests.session()
session.headers = {}
session.proxies = {}
session.verify = False
return session
class SomeApi:
session = CachedSession()
def __init__(self):
self.api_key = '123'
def disconnect(self):
self.__class__.session.close()
self.__class__.session = None
def request(self):
print(f'making request using session ID {id(self.session)}')
some_api1 = SomeApi()
some_api2 = SomeApi()
some_api1.request()
some_api1.request()
some_api2.request()
some_api1.disconnect()
some_api1.request()
some_api1.request()
some_api2.request()
# prints OK:
# making request using session ID 1291988425360
# making request using session ID 1291988425360
# making request using session ID 1291988425360
# making request using session ID 140726378118360
# making request using session ID 140726378118360
# making request using session ID 140726378118360
But is it the proper way to do it?
Having to use __class__
feels a little hackish, but if I remove it, only instance session will get reset.
It also does not feel entirely right that I use instance method (disconnect
) to reset all other instances.
Then I do not like the fact that connect
and disconnect
belong to different classes, ideally I would like to have them both on the CachedSession
descriptor (but how do I call disconnect
then?)
To implement CachedSession
with a singleton instance you should define it as a class property
Having to use
__class__
feels a little hackish, but if I remove it, only instance session will get reset.
Instead of __class__
property you also could define the method as a @classmethod
like below
class CachedSession:
_session = None
def __get__(self, *args, **kwargs):
return self.connect()
@classmethod
def connect(cls):
if not cls._session:
cls._session = requests.session()
cls._session.headers = {}
cls._session.proxies = {}
cls._session.verify = False
return cls._session
@classmethod
def disconnect(cls):
if cls._session:
cls._session.close()
cls._session = None
Then I do not like the fact that connect and disconnect belong to different classes, ideally I would like to have them both on the CachedSession descriptor (but how do I call disconnect then?)
As you can see the disconnect
already is a @classmethod
of CachedSession
which means that it is able to change any class property as well as _session
. So after disconnecting the session will be disconnected all instances of the class while __get__
have not been called yet. To disconnect the session just call CachedSession.disconnect()
.
class SomeApi:
session = CachedSession()
def request(self):
print(f'making request using session ID {id(self.session)}')
some_api1 = SomeApi()
some_api2 = SomeApi()
some_api1.request() # making request using session ID 139839142708616
some_api1.request() # making request using session ID 139839142708616
some_api2.request() # making request using session ID 139839142708616
CachedSession.disconnect()
some_api1.request() # making request using session ID 139839142240040
some_api1.request() # making request using session ID 139839142240040
some_api2.request() # making request using session ID 139839142240040