为 class 的所有实例重置由描述符缓存的 属性

Reset property cached by descriptor for all instances of class

我想在多个 class 实例之间共享 requests 会话,并且还能够为所有此类实例重置会话。

所以我有 disconnect 重置所有实例会话的方法:

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

但这是正确的做法吗?

不得不使用 __class__ 感觉有点老套,但如果我删除它,只会重置实例会话。

我使用实例方法(disconnect)重置所有其他实例也感觉不完全正确。

然后我不喜欢 connectdisconnect 属于不同的 classes,理想情况下我希望它们都在 CachedSession 描述符中(但是我怎么调用 disconnect 呢?)

要使用单例实例实现 CachedSession,您应该将其定义为 class 属性

Having to use __class__ feels a little hackish, but if I remove it, only instance session will get reset.

而不是 __class__ 属性 您也可以将方法定义为 @classmethod 如下所示

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

如您所见,disconnect 已经是 CachedSession@classmethod,这意味着它也可以更改任何 class 属性作为 _session。因此,在断开会话后,class 的所有实例都将断开连接,而 __get__ 尚未被调用。要断开会话,只需调用 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