【问题标题】:How can I use a context manager to define an actual context for instantiation of new classes?如何使用上下文管理器为新类的实例化定义实际上下文?
【发布时间】:2021-11-12 15:35:59
【问题描述】:

我有以下问题。我有多个单元测试,每个单元测试都有一个上下文管理器来打开浏览器并进行一些硒测试。

我想确保我可以并行运行测试,并且在出现错误时关闭浏览器窗口,所以我使用了上下文管理器:

def test_xxx():
    with webapp() as p:                                                                   
        file_loader = FileLoader(p, id="loader").upload(path)

如您所见,我使用了一个 FileLoader 类,它采用上下文管理器 Web 应用程序(基本上是 selenium 驱动程序的一个包装器)并使用它来封装上传文件所需的繁琐程序。

我的目标是不必为 FileLoader() 指定 p 参数,以便我可以编写

def test_xxx():
    with webapp():                                                                   
        file_loader = FileLoader(id="loader").upload(path)

我可以使用在打开上下文管理器时分配的全局变量,但这会在测试并行运行时阻止任何隔离。假设一个测试连接到站点 A,另一个测试连接到站点 B。我需要两个驱动程序,每个驱动程序连接到不同的站点。

换句话说,我如何设计 FileLoader 以在不传递上下文变量的情况下了解其封闭的上下文管理器?

【问题讨论】:

  • “我的目标是……” 为什么?这真的值得吗?它的方式不是更明确吗?
  • “并行”是指并发(即在不同线程中)吗? explicit is better than implicit,所以我非常喜欢FileLoader(p, id="loader") 版本而不是FileLoader(id="loader")。想象一下阅读类似with open('data.json'): data = json.load() 的内容;它只是看起来不那么清楚。或者,您可以设计一个FileLoaderWebapp 作为上下文管理器,它包装了webapp()FileLoader(...) 的东西,然后将其用作with FileLoaderWebapp() as p: p.upload(path)
  • 我同意@tobias_k 的观点,你必须有一些理由这样做,但从你分享的内容中不清楚,所以很难提供帮助。隐藏参数的另一种简单方法是首先创建functools.partialpFileLoader = partial(FileLoader, p)。然后 pFileLoader 在没有 arg 的情况下工作,但上下文化为 p

标签: python


【解决方案1】:

通过使用inspect 模块,代码可以读取其调用者的局部变量。如果不危险的话,这是一种相当不寻常的用途,因为它实际上归结为一种将参数传递给函数的非标准和非传统方式。但如果你真的想走那条路,这个另一个SO question 提供了一种可能的方式。

演示:

class ContextAware:
    """ Class that will copy  the x local variable of its caller if any"""
    def __init__(self):
        # uncomment next line for debugging
        # print("ContextAware", inspect.currentframe().f_back.f_locals)
        self.x = inspect.currentframe().f_back.f_locals.get('x')

        
def foo(x):
    # the value of x is not explicitely passed, yet it will be used...
    return ContextAware()

在 foo 中创建的对象知道其调用者的 x 变量:

>>> a = foo(4)
>>> a.x
4
>>> a = foo(6)
>>> a.x
6

这意味着你可以写出接近于:

def test_xxx():
    with webapp() as ctx_p:
        file_loader = FileLoader(id="loader").upload(path)

在调用者的ctx_p局部变量上提供FileLoader__init__方法间谍

【讨论】:

  • 很好。正如你所说,这有点不寻常,但我想知道你是否还有一些设计建议来创造一些感觉更自然的东西。
  • AFAIK,自然的方法是将参数显式传递给函数或构造函数
猜你喜欢
  • 2012-12-20
  • 2019-05-30
  • 1970-01-01
  • 1970-01-01
  • 2014-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-28
相关资源
最近更新 更多