不使用类作为上下文管理器时,是否可以自动调用进入和退出方法?

时间:2018-08-11 08:57:07

标签: python

我为PyQt做了一个上下文管理器包装,其中__enter__将设置布局或小部件,而__exit__将其应用于父布局。基本上,它减少了创建布局所需的代码行,并且与缩进效果很好。

如果我想访问某些方法(例如remove_border,如果它是QTreeWidget),我将在小部件上使用包装器,但是我需要这样调用代码:

with MyClass(QtWidgets.QTreeWidget, parent_layout) as widget:
    pass

是否有可能让我可以做widget = MyClass(QtWidgets.QTreeWidget, parent_layout),但仍然可以运行enter和exit方法?

编辑:基于code_onkel的答案,我分离了功能,但保持了相当简单,因此很多工作是自动完成的。

下面是一个QPushButton的示例:

class Example(object):
    ...

    def addQPushButton(self, *args, **kwargs):
        with QWidgetPushButton(self, *args, **kwargs) as widget:
            return widget

    @contextmanager
    def QPushButton(self, *args, **kwargs):
        with QWidgetPushButton(self, *args, **kwargs) as widget:
            yield widget


with Example(parent) as layout:
    button_1 = layout.addQPushButton('1')
    with layout.QPushButton('2') as button_2:
        pass

1 个答案:

答案 0 :(得分:0)

我认为解决此问题的最优雅的方法是稍微调整一下工厂模式,并添加包装函数以与工厂类进行交互。请参见下面的代码,其中有一个create_simple()方法不是上下文管理器。恕我直言,这比在不需要上下文时强制执行上下文管理器要干净得多。如果您坚持使用单个工厂函数,则需要一个参数来告诉工厂是否要使用上下文管理器或简单的小部件(请参见create2())。

import contextlib

class WidgetFactory:
    def __init__(self, widget_cls, parent=None):
        self.widget_cls = widget_cls
        self.widget = None
        self.parent = parent

    def create_widget(self):
        # create widget
        self.widget = object()

    def setup_widget(self):
        # do stuff
        pass

    def apply_to_parent(self):
        # do suff
        pass

    @contextlib.contextmanager
    def create(self):
        self.create_widget()
        self.setup_widget()
        yield self.widget
        self.apply_to_parent()

    def create_simple(self):
        self.create_widget()
        self.setup_widget()
        self.apply_to_parent()
        return self.widget

def create(*args, **kwargs):
    return WidgetFactory(*args, **kwargs).create()

def create_simple(*args, **kwargs):
    return WidgetFactory(*args, **kwargs).create_simple()

def create2(*args, context=False, **kwargs):
    factory =  WidgetFactory(*args, **kwargs)
    if context:
        return factory.create()
    else:
        return factory.create_simple()

def main():
    root = create_simple('dummy for qt class')

    with create('dummy for qt class', root) as child:
        # do stuff with child
        print(child)

    simple_child = create_simple('dummy for qt class', root)
    print(simple_child)

if __name__ == '__main__':
    main()