代码之家  ›  专栏  ›  技术社区  ›  Igor Pozdeev

属性getter和上下文管理器

  •  3
  • Igor Pozdeev  · 技术社区  · 6 年前

    我希望以这样的方式定义一个属性,即无论何时调用它,它都是在上下文管理器中完成的。比如,我从以下内容开始:

    @property
    def hangar(self):
        return self._hangar
    

    每当我写下代码时:

    res = some_function(self.hangar)
    

    我希望评估为:

    with pandas.HDFStore(...) as hangar:
        some_function(self.hangar)
    

    有什么想法吗?

    2 回复  |  直到 6 年前
        1
  •  1
  •   jsbueno    6 年前

    从评论中可以看出,您需要的是某种程度上“由内而外”的上下文管理器的工作方式。

    但这并不能阻止您让函数调用/属性检索“由内向外”:您所需要的是,不要使用“property”调用所需的方法,而是将目标函数作为参数传递。

    这方面的一些东西:

    def context_property(method):
        def wrapper(self, target, *args, **kw):
            path = method(self)
            with pandads.HDFStore(path) as context:
                result = target(context, *args, **kw)
            return result
        return wrapper
    
    class MyClass:
        @context_property
        def hangar(self):
            return "path_to_hdfstore"
    
        def do_stuff(self):
            ...
            value = self.hangar(some_function)
            ...
    

    some_function 将在上下文管理器中运行。如果您需要使上下文管理器本身具有通用性,并且不总是“pandas.HDFStore”,那么您可以在装饰器上增加一个级别来配置它。

        2
  •  1
  •   charli    3 年前

    接受的答案是正确的,但有类似的问题,我选择创建一个属性,它也是一个上下文管理器。因此,我们的想法是将该属性用作上下文管理器 总是 .

    在您的情况下:

    @property
    def hangar(self):
        return pandas.HDFStore(...)
    

    然后使用 with :

    with self.hangar as hangar:
       res = some_function(hangar)
    

    这允许您更改 hangar 非上下文管理器的定义(例如在子类中)。在这种情况下,您需要装饰您的方法:

    @property
    @contextmanager
    def hangar(self):
        yield self._hangar
    

    它仍然在工作。记住装饰师的命令 事项 yield 而不是 return .