如何将uopy_session传入全局config对象的__enter__方法?
问题详情
我用全局变量存储代码全程需要的配置数据,当前代码结构如下:
config_object = None def init_config(config_file=CONFIG_PATH): # 一些初始化代码... global config_object config_object = U2DBLiveConfig(config_file) def get_config(): if not config_object: init_config() return config_object
我给U2DBLiveConfig类加了__enter__和__exit__方法,方便和其他session对象一起使用时标记状态:
class U2DBLiveConfig: def __init__(self, config_file_path=CONFIG_PATH): self.__uopy_session_opened = False # 其他初始化代码 def __enter__(self): self.__uopy_session_opened = True return self def __exit__(self, exc_type, exc_val, exc_tb): self.__uopy_session_opened = False
现在我通过with语句同时使用两个对象:
with create_uopy_session() as uopy_session, get_config() as cfg: # 这里__uopy_session_opened标记已设为True
我希望把uopy_session对象传入__enter__方法,这样就能在其他地方通过config_object访问它。注意config_object可能在调用with语句之前就已经创建了,所以没法通过__init__方法传入。能不能实现类似下面的功能?
class U2DBLiveConfig: def __init__(self, config_file_path=CONFIG_PATH): self.__uopy_session_opened = False self.__uopy_session = None # 其他初始化代码 def __enter__(self, **kwargs): self.__uopy_session_opened = True self.__uopy_session = kwargs['uopy_session'] return self def __exit__(self, exc_type, exc_val, exc_tb): self.__uopy_session_opened = False self.__uopy_session = None
可行解决方案
原生Python的上下文管理器协议里,__enter__方法不支持额外参数,所以直接修改它的签名加**kwargs是行不通的,with语句不会自动给它传参。不过有几种办法能实现你的需求:
方法1:给配置类加显式的会话绑定方法
在U2DBLiveConfig里新增一个绑定会话的方法,然后在with块里手动调用:
class U2DBLiveConfig: def __init__(self, config_file_path=CONFIG_PATH): self.__uopy_session_opened = False self.__uopy_session = None # 其他初始化代码 def __enter__(self): self.__uopy_session_opened = True return self def __exit__(self, exc_type, exc_val, exc_tb): self.__uopy_session_opened = False self.__uopy_session = None def bind_uopy_session(self, session): self.__uopy_session = session
使用时:
with create_uopy_session() as uopy_session, get_config() as cfg: cfg.bind_uopy_session(uopy_session) # 此时cfg的__uopy_session已绑定,其他地方通过config_object就能访问
方法2:自定义上下文生成器函数
如果想让with语句更简洁,可以写个生成器函数封装绑定逻辑:
def config_with_session(session): cfg = get_config() cfg.__uopy_session_opened = True cfg.__uopy_session = session try: yield cfg finally: cfg.__uopy_session_opened = False cfg.__uopy_session = None
使用时:
with create_uopy_session() as uopy_session, config_with_session(uopy_session) as cfg: # 会话已自动绑定到cfg,直接使用即可
方法3:调整with语句结构(不推荐)
如果允许先创建会话再处理配置,可以这样写,但因为你提到config可能提前创建,这个方法适用性有限:
with create_uopy_session() as uopy_session: cfg = get_config() cfg.__uopy_session = uopy_session cfg.__uopy_session_opened = True try: # 这里写业务逻辑 finally: cfg.__uopy_session_opened = False cfg.__uopy_session = None
关键提醒
- 原生上下文协议的
__enter__没有参数入口,没法通过with语句直接传参给它。 - 优先推荐方法1,代码逻辑清晰,符合面向对象封装原则,还不会破坏原有的全局配置初始化流程。
内容的提问来源于stack exchange,提问作者Héctor C.
相关产品推荐
相关产品推荐

