Python 通过函数调用使上下文管理器对象保持活动状态
我在通过函数调用保持上下文管理器打开方面遇到了一些问题。我的意思是: 在一个模块中定义了一个上下文管理器,我使用它打开到网络设备的SSH连接。“设置”代码处理打开SSH会话和处理任何问题,而拆卸代码处理优雅地关闭SSH会话。我通常使用它如下:Python 通过函数调用使上下文管理器对象保持活动状态,python,ssh,network-programming,paramiko,contextmanager,Python,Ssh,Network Programming,Paramiko,Contextmanager,我在通过函数调用保持上下文管理器打开方面遇到了一些问题。我的意思是: 在一个模块中定义了一个上下文管理器,我使用它打开到网络设备的SSH连接。“设置”代码处理打开SSH会话和处理任何问题,而拆卸代码处理优雅地关闭SSH会话。我通常使用它如下: from manager import manager def do_stuff(device): with manager(device) as conn: output = conn.send_command("show ip
from manager import manager
def do_stuff(device):
with manager(device) as conn:
output = conn.send_command("show ip route")
#process output...
return processed_output
def do_stuff(device, return_handle=False):
with manager(device) as conn:
output = conn.send_command("show ip route")
#process output...
if return_handle:
return (processed_output, conn)
else:
return processed_output
为了保持SSH会话处于打开状态,并且不必跨函数调用重新建立它,我想在“do_stuff”中添加一个参数,该参数可以选择返回SSH会话以及从SSH会话返回的数据,如下所示:
from manager import manager
def do_stuff(device):
with manager(device) as conn:
output = conn.send_command("show ip route")
#process output...
return processed_output
def do_stuff(device, return_handle=False):
with manager(device) as conn:
output = conn.send_command("show ip route")
#process output...
if return_handle:
return (processed_output, conn)
else:
return processed_output
我希望能够从另一个函数调用这个函数“dou-stuff”,如下所示,这样它就可以向“dou-stuff”发出信号,表示SSH句柄应该与输出一起返回
def do_more_stuff(device):
data, conn = do_stuff(device, return_handle=True)
output = conn.send_command("show users")
#process output...
return processed_output
然而,我遇到的问题是,由于do_stuff函数“返回”并触发上下文管理器中的拆卸代码,SSH会话被关闭(这将优雅地关闭SSH会话)
我已尝试将“do_stuff”转换为生成器,使其状态处于挂起状态,并可能导致上下文管理器保持打开状态:
def do_stuff(device, return_handle=False):
with manager(device) as conn:
output = conn.send_command("show ip route")
#process output...
if return_handle:
yield (processed_output, conn)
else:
yield processed_output
并称之为:
def do_more_stuff(device):
gen = do_stuff(device, return_handle=True)
data, conn = next(gen)
output = conn.send_command("show users")
#process output...
return processed_output
然而,在我的例子中,这种方法似乎不起作用,因为上下文管理器关闭了,而我得到了一个关闭的套接字
有没有更好的方法来解决这个问题?也许我的生成器需要做更多的工作……我认为使用生成器保持状态是我想到的最“明显”的方式,但总的来说,我是否应该寻找另一种在函数调用中保持会话打开的方式
谢谢我发现了这个问题,因为我正在寻找一个类似问题的解决方案,其中我想要保持活动状态的对象是一个包含selenium.webdriver.Firefox实例的pyvirtualdisplay.display.display实例 我还希望,如果在显示/浏览器实例创建过程中引发异常,那么任何打开的资源都会消失 我想同样的方法也可以应用于数据库连接 我认识到这可能只是一个部分解决方案,包含的最佳实践不多。谢谢你的帮助 此答案是临时使用以下资源修补我的解决方案的结果:
kwargs = {
'rfbport': 5904,
}
_desktop_manager = XvncDesktopManager(check_desktop_display_ok=check_desktop_display_ok, **kwargs)
with ExitStack() as stack:
# context entered and what is inside the __enter__ method is executed
# desktop_manager will have an attribute "close_all" that can be called explicitly to unwind the callback stack
desktop_manager = stack.enter_context(_desktop_manager)
# I was able to manipulate the browsers inside of the display
# and outside of the context
# before calling desktop_manager.close_all()
browser, = desktop_manager.browser_resources
browser.get(url)
# close everything down when finished with resource
desktop_manager.close_all() # does nothing, not in callback stack
# this functioned as expected
desktop_manager.release_desktop_display(desktop_manager)
我发现这个问题是因为我正在寻找一个类似问题的解决方案,其中我想要保持活动状态的对象是一个pyvirtualdisplay.display.display实例,其中包含selenium.webdriver.Firefox实例 我还希望,如果在显示/浏览器实例创建过程中引发异常,那么任何打开的资源都会消失 我想同样的方法也可以应用于数据库连接 我认识到这可能只是一个部分解决方案,包含的最佳实践不多。谢谢你的帮助 此答案是临时使用以下资源修补我的解决方案的结果:
kwargs = {
'rfbport': 5904,
}
_desktop_manager = XvncDesktopManager(check_desktop_display_ok=check_desktop_display_ok, **kwargs)
with ExitStack() as stack:
# context entered and what is inside the __enter__ method is executed
# desktop_manager will have an attribute "close_all" that can be called explicitly to unwind the callback stack
desktop_manager = stack.enter_context(_desktop_manager)
# I was able to manipulate the browsers inside of the display
# and outside of the context
# before calling desktop_manager.close_all()
browser, = desktop_manager.browser_resources
browser.get(url)
# close everything down when finished with resource
desktop_manager.close_all() # does nothing, not in callback stack
# this functioned as expected
desktop_manager.release_desktop_display(desktop_manager)