在Python上下文管理器中观察到的可怕操作

2024-09-29 23:27:48 发布

您现在位置:Python中文网/ 问答频道 /正文

在Python3中使用contextmanager(我还没有测试Python2)对于在with子句范围内声明的变量有一些奇怪的行为

在我看来,这些变量的行为就像是“远处的幽灵行动”,因为只有在观察到它们时,它们才似乎存在(一个不懂物理的工程师开的玩笑

在上下文管理器范围内,屈服点之后:

如果你

  1. 打印出locals()

那么变量不存在

但如果你:

  1. 打印出locals()
  2. 对托管范围的变量执行任何操作

那么变量存在

请参见此示例:

from contextlib import contextmanager

def groucho():
    @contextmanager
    def groucho_manager(**kwargs):
        yield
        print("groucho_manager locals", locals())
        a

    with groucho_manager(lolcat=10):
        a = 50

def harpo():
    @contextmanager
    def harpo_manager(**kwargs):
        yield
        print("harpo_manager locals", locals())

    with harpo_manager(lolcat=10):
        b = 100

groucho()
harpo()

产出:

groucho_manager locals {'kwargs': {'lolcat': 10}, 'a': 50}
harpo_manager locals {'kwargs': {'lolcat': 10}}

可能与Python class inheritance - spooky action有关,但我不确定


Tags: 声明defwithmanagerpython3kwargsprintyield
1条回答
网友
1楼 · 发布于 2024-09-29 23:27:48

我最初的用例是制作一个inner scope aware context manager来处理日志记录

我认为我可以滥用问题中列出的奇怪行为,但正如@jasonharper所指出的:这与嵌套作用域有关,不能滥用

所以。。。我决定为所有这些问题制定一个真正骇客/滥用的解决方案:

关于pypi的scope_injected_contextmanager

以下是自述文件中的简单示例:

from scope_injected_contextmanager import scope_injected_contextmanager

fetch = lambda request: ("ok", 200)

@scope_injected_contextmanager
def log_request(request, response):
    print(f"request: {request} response: {response}")

with log_request:
    request = {
        "query_args": {
            'foo': 10
        }
    }
    response = fetch(request)

# prints
# request: {'query_args': {'foo': 10}} response: ('ok', 200)

详见github

小心。。。its:

  1. 真讨厌
  2. 完全没有足够的测试
  3. 真的很难看而且虐待人
  4. 大量使用inspect(见1-3)

相关问题 更多 >

    热门问题