You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何自定义上下文管理器with块内return会退出__enter__函数

问题解答:上下文管理器__enter__中return的行为

核心原因:return的本质是终止当前函数

不管你在多少层嵌套代码块(比如with、if、for)里用return,它的作用都是立刻终止当前所在的函数,并返回指定值。在你的代码里,return len(self.response.content)写在self.session.get(...)的嵌套with块中,但这个return属于__enter__函数,所以执行到这行时,会直接结束整个__enter__函数,自然不会跑后面的print("I would expect...")这些代码。

另外,上下文管理器的__enter__方法的返回值会绑定到with ... as manager里的manager变量,这也是为什么你的manager最终拿到的是响应内容长度的原因。

修正方案:调整return的位置

如果想执行完嵌套with块的登录逻辑后,继续跑__enter__后续的代码,得把return移到嵌套with块外面,示例代码如下:

import requests

class LoginLogoutContextManager:
    def __enter__(self):
        print("**entered __enter__")
        print("Logging in...")

        self.url = "http://www.google.com"
        self.session = requests.Session()
        response_length = 0

        with self.session.get(self.url) as self.response:
            print("Start Login attempt (inside WITH but before RETURN)")
            response_length = len(self.response.content)
            print("Login complete (inside WITH after assigning value)")

        # 现在会执行这里的代码了
        print("Now we're back to __enter__ code after nested WITH")
        print("!!exiting __enter__")
        # 最后再返回需要绑定给manager的值
        return response_length

    def __exit__(self, exc_type, exc_value, exc_tb):
        print("**entered __exit__")
        print("Logging OUT...")
        # 这里可以添加实际的登出逻辑,比如调用登出API
        print("!!exiting __exit__")


with LoginLogoutContextManager() as manager:
    print("Cool now the Login/Logout API calls are handled for me")
    print(f"Login attempt response length: {manager}")

修正后的运行输出

**entered __enter__
Logging in...
Start Login attempt (inside WITH but before RETURN)
Login complete (inside WITH after assigning value)
Now we're back to __enter__ code after nested WITH
!!exiting __enter__
Cool now the Login/Logout API calls are handled for me
Login attempt response length: 14126
**entered __exit__
Logging OUT...
!!exiting __exit__

额外提示:贴合场景的上下文管理器写法

你的需求是用上下文管理器处理登录/登出,更合理的做法是把session对象作为__enter__的返回值,这样在with块里能直接用这个session执行后续API操作:

import requests

class LoginLogoutContextManager:
    def __enter__(self):
        print("**entered __enter__")
        print("Logging in...")

        self.url = "http://www.google.com"
        self.session = requests.Session()
        # 模拟登录:实际这里应该调用登录API,比如post登录接口
        with self.session.get(self.url) as response:
            print("Login attempt completed")
        
        print("!!exiting __enter__")
        # 返回session,方便后续操作
        return self.session

    def __exit__(self, exc_type, exc_value, exc_tb):
        print("**entered __exit__")
        print("Logging OUT...")
        # 模拟登出:实际调用登出API
        # self.session.post(logout_url)
        self.session.close()
        print("!!exiting __exit__")


with LoginLogoutContextManager() as session:
    print("Cool now the Login/Logout API calls are handled for me")
    # 使用session执行其他API操作
    # response = session.get(other_api_url)
    print("Finished other API operations")

内容的提问来源于stack exchange,提问作者Jones Smith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 22:45:40