代码之家  ›  专栏  ›  技术社区  ›  barciewicz

如何将延迟加载的属性转换为描述符?

  •  0
  • barciewicz  · 技术社区  · 4 年前

    我有以下代码可以重复使用 requests 多个请求之间的会话:

    import requests
    
    class SomeApi():
        _session = None
    
        def __init__(self):
            self.api_key = '123'
    
        @property
        def session(self):
            if self._session is None:
                self._session = self.connect()
            return self._session
    
        @staticmethod
        def connect():
            print("Connecting to SomeAPI API")
            session = requests.session()
            session.headers = {'Accept-Encoding': 'deflate,gzip'}
            session.verify = False
            return session
    
        def request(self):
            print(f'Making request with session ID {id(self.session)}')
    
    
    some_api = SomeApi()
    
    # make some requests reusing the session
    some_api.request() 
    some_api.request() 
    some_api.request()
    

    它有效,但我想使用描述符而不是会话的属性。所以我想出了这样的办法:

    import requests
    
    class InitOnAccess:
        def __init__(self, init_func, *args, **kwargs):
            self.klass = init_func
            self.args = args
            self.kwargs = kwargs
            self._initialized = None
        
        def __get__(self, instance, owner):
            if self._initialized is None:
                self._initialized = self.klass(*self.args, **self.kwargs)
            return self._initialized
    
    class SomeApi():  
        session = InitOnAccess(self.connect)
    
        def __init__(self):
            self.api_key = '123'
    
        @staticmethod
        def connect():
            print("Connecting to SomeAPI API")
            session = requests.session()
            session.headers = {'Accept-Encoding': 'deflate,gzip'}
            session.verify = False
            return session
    
        def request(self):
            print(f'Making request with session ID {id(self.session)}')
    
    
    some_api = SomeApi()
    
    # make some requests reusing the session
    some_api.request() 
    some_api.request() 
    some_api.request()
    

    但它将提高:

        session = InitOnAccess(self.connect)
    NameError: name 'self' is not defined 
    

    我能想到的解决办法之一就是搬家 connect 课外,但我想保留封装。 另一种方法是编写一个特定的描述符,比如 RequestsSession 而不是 InitOnAccess 并定义所有 连接 逻辑在那里,但我想保留 InitOnAccess 类,以便在其他地方重复使用。

    我还有别的办法可以修吗?

    1 回复  |  直到 4 年前
        1
  •  1
  •   Simon Hawe    4 年前

    如果你使用的是python 3.10,并且不介意改变,你可以在connect方法之后定义会话,然后直接传入 self 无论如何,这是一种静态方法

    class SomeApi():
    
        def __init__(self):
            self.api_key = '123'
    
        @staticmethod
        def connect():
            print("Connecting to SomeAPI API")
            session = requests.session()
            session.headers = {'Accept-Encoding': 'deflate,gzip'}
            session.verify = False
            return session
    
        def request(self):
            print(f'Making request with session ID {id(self.session)}')
    
        session = InitOnAccess(connect)
    

    如果你还没有使用python 3.10,你可以这样做

    class SomeApi():
    
        def __init__(self):
            self.api_key = '123'
    
        @staticmethod
        def connect():
            print("Connecting to SomeAPI API")
            session = requests.session()
            session.headers = {'Accept-Encoding': 'deflate,gzip'}
            session.verify = False
            return session
    
        def request(self):
            print(f'Making request with session ID {id(self.session)}')
    
        session = InitOnAccess(connect.__get__(object))
    

    然而,这看起来相当粗鲁。

    我建议搬家 connect 从您的类中取出,并且不要将其作为静态方法。对我来说似乎没有那么粗鲁和干净。

    推荐文章