如何从 with 语句中 return ?

How to return from with statement?

我有一个函数尝试连接到 ftp 的一些参数列表并连接到它可以连接到的第一个服务器。

def connect(params):
    for user, passw, host in params:
        try:
            import pdb;pdb.set_trace()
            with FTPHost(host, user, passw) as h:
                return h
        except FTPError as e:
            logger.debug("Can't connect to ftp error is {}".format(e))
    else:
        raise Exception(
            "Can't connect to ftp server with none of the {}".format(params)
        )

在代码中我正在尝试类似的东西

host = connect(*args)
host.walk()

但是在 return 之后连接就关闭了。这可能是它应该如何工作,我想,虽然我希望它不会。 但是现在我真的不知道如何正确地封装来自应用程序逻辑的连接试验。

我的意思是我当然可以将其更改为连续传递样式(这是正确的名称,对吧?)

def connect(params, some_application_function):
    for user, passw, host in params:
        try:
            import pdb;pdb.set_trace()
            with FTPHost(host, user, passw) as host:
                some_application_function(host)
        except FTPError as e:
            logger.debug("Can't connect to ftp error is {}".format(e))
    else:
        raise Exception(
            "Can't connect to ftp server with none of the {}".format(params)
        )

但这似乎不太可读。还有其他选择吗?

也许将 with 语句移到 connect 函数之外?

def connect(params):
    for user, passw, host in params:
        try:
            import pdb;pdb.set_trace()
            return FTPHost(host, user, passw)
        except FTPError as e:
            logger.debug("Can't connect to ftp error is {}".format(e))
    else:
        raise Exception(
            "Can't connect to ftp server with none of the {}".format(params)
        )

def main():
    with connect(params) as h:
        do_something(h)

我可能会将您的 connect 函数转换为内部调用您的 FTPHost 上下文管理器的魔术方法的上下文管理器本身:

class FTPConnector:
    def __init__(self, params):
        self.params = params
    def __enter__(self):
        for user, passw, host in params:
            try:
                # import pdb;pdb.set_trace()  # not sure what you want to do with that...
                self.h_context = FTPHost(host, user, passw)
                return self.h_context.__enter__()
            except FTPError as e:
                logger.debug("Can't connect to ftp error is {}".format(e))
        else:
            raise Exception(
                "Can't connect to ftp server with none of the {}".format(params)
            )
    def __exit__(self, exc_type, exc_value, traceback):
        return self.h_context.__exit(exc_type, exc_value, traceback)

现在您可以 运行 在您的主函数中这样做:

with FTPConnector(params) as host:
    host.walk()
    # do something useful with the connection here

# here the connection gets closed again