如何访问在`with`语句中创建的变量

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

我在文件中定义了python上下文类和Test类:

class Test(object):
  pass

class MyContext(object):
  def __init(self):
     self._vars = []
  def __enter__(self):
    pass
  def __exit(self, ....):
    pass

在使用该上下文的另一个文件中:

from somewhere import Test, MyContext
with MyContext() as ctx:
  mytest = Test()

所以我想要实现的是,当我退出上下文时,我想知道创建的mytest实例并将其添加到ctx._vars = [<instance of Test >]中。

我不想具有ctx.add_var(mytest)方法,我希望将那些Test实例自动添加到ctx实例。

python introspection
1个回答
0
投票

可以使用Python的自省功能来完成,但是您必须意识到这不是为with上下文块创建的。

我同意,这是一种有用的语法构造,可以“偏离”以执行所需的操作:注释“注册表”中代码块内创建的对象。

[在显示如何使用上下文管理器执行此操作之前,请考虑类主体是否足以满足您的需求。以这种方式使用类主体也偏离了其主要目的,但是您可以免费使用“注册表”:


from somewhere import Test, MyContext
class ctx:
  mytest = Test()

vars = ctx.__dict__.values()

为了使用上下文管理器执行此操作,必须在with块的开头和结尾检查局部变量。虽然这并不难,但它不会涵盖创建的Test的所有实例-因为如果代码是这样的:

mytests = []
with Mycontext as ctx:
    mytests.append(Test())

没有创建新变量-因此跟踪局部变量的代码将找不到任何内容。可以编写代码来递归地查看带有容器的变量,例如字典和列表-但然后可以将mytest()实例添加到引用为全局变量或其他模块中的变量的容器中。

事实证明,跟踪Test实例的可靠方法是检测Test类本身,以在注册表中注释新实例。这要容易得多,并且在“局部变量自省”技巧上的用处不大。

该代码有点像:


class Test(object):
  pass

class MyContext(object):
    def __init(self, *args):
        self.vars = []
        self.track = args
        self.original_new = {}

    def patch(self, cls_to_patch):
        cls_new = getattr(cls_to_patch, "__new__")
        if "__new__" in cls.__dict__:
            self.original_new[cls_to_patch] = cls_new

        def patched_new(cls, *args, **kwargs):
            instance = cls_new(*args, **kwags)
            self.vars.append(instance)
            return instance

        cls_to_patch.__new__ = patched_new        

    def restore(self, cls):
        if cls in self.original_new:
            # class had a very own __new_ prior to patching
            cls.__new__ = self.original_new[cls]
        else:
            # just remove the wrapped new method, restores access to superclass `__new__`
            del cls.__new__

    def __enter__(self):
        for cls in self.track:
            self.patch(cls)
        return self

    def __exit(self, ....):
        for cls in self.track:
            self.restore(cls)
        ...


from somewhere import Test, MyContext
with MyContext(Test) as ctx:
  mytest = Test()

© www.soinside.com 2019 - 2024. All rights reserved.