在 Python 生成器中使用“with”语句管理资源

问题描述 投票:0回答:1

今天,在编程时,我发现自己在生成器函数内管理资源(ssh 连接),类似于以下内容:

def _yield_fname(host_address, usr, pwd, datapath):
    with paramiko.SSHClient() as ssh_client:

        ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        ssh_client.connect(host, username=usr, password=pwd)
        
        stdin, stdout, stderr = ssh_client.exec_command(
            'find . -type d -maxdepth 1 -printf "%f\n"'
        )
        for line in stdout:
            yield fname

def get_foos():

    foos= []
    for fname in self._yield_fname(self.FOO_PATH):
        foos.append(Foo.from_fname(fname))
    
    return foos

def get_bars():

    bars= []
    for fname in self._yield_fname(self.FOO_PATH):
        bars.append(Bar.from_fname(fname))
    
    return bars

以这种方式管理生成器函数内的资源是不好的做法吗?

就我而言,我计划从头到尾始终消耗

yield_fname
的生成器,以便连接始终关闭。我是否应该担心有人(例如未来的我)使用生成器而没有完全消耗它并保持连接打开?有办法防止吗?

(作为旁注,这里我决定使用生成器函数,因为我想避免循环遍历文件名列表两次或多次)。

python yield with-statement
1个回答
3
投票

以这种方式管理生成器函数内的资源是不好的做法吗?

IMO 不,这是很正常的用法

我是否应该担心有人(例如未来的我)使用生成器而没有完全消耗它并保持连接打开?

可能不是,但这可能是一个问题。我相当确定(如所写),只要生成器尚未耗尽或垃圾收集,上下文管理器就会“存活”。

不过,我通常不会担心这一点,在大多数 Python 用例的上下文中,这是一种性能/资源边缘情况,其中严格的性能和资源管理并不是高优先级。

有办法防止这种情况吗?

您可以在生成器外部创建上下文,并将其传入。即使生成器没有耗尽,您仍然可以退出上下文。

gen = None  # even if we keep generator from being garbage collected
found = None
with get_resource() as res:
    gen = build_generator(res)
    for item in gen:
        if desired(item):
            found = item
            break  # incomplete iteration

print(item)
© www.soinside.com 2019 - 2024. All rights reserved.