5

对象清理似乎是我在编程期间遇到的一个非常常见的问题。迄今为止,我一直使用此处with推荐的声明

今天我有另一个想法,这对我来说似乎更优雅(因为它不需要最终用户的 with 声明)。这个想法是对某种类型的对象使用 try-finally 装饰器(具有清理方法)。

只是想知道这种做法是否有任何问题,或者是否有更好的方法。我不喜欢我的许多类需要使用 with 语句进行初始化,但我也想确保我的对象正确关闭。这是一个简短的例子。

def cleanme(func):
    def _decorator(self, *args, **kwargs):
        try:
            func(self, *args, **kwargs)
        finally:
            self._cleanup()

    return _decorator


class IObject(object):
    def __init__(self):
        self.file_name = "some_file.txt"
        self._file_object = None
        self._cleaned = True

    @cleanme
    def run(self):
        self._connect()
        while True:
            # do some things over a long period
            pass

    def _connect(self):
        self._file_object = open(self.file_name)
        self._cleaned = False

    def _cleanup(self):
        if not self._cleaned:
            self._file_object.close()
            self._cleaned = True
4

2 回答 2

3

让我在这上面打几个洞。

一个想法,你要求你的班级有一个cleanup(),它被声明在与 不同的地方run()。因此,您要强制用户负责干净地实施和维护它。

析构__exit__函数在 Python 中非常少见,因此资源获取代码可能会偏离cleanup()代码,造成泄漏。

其次,您正在创建file_object一个实例变量,从而从单个函数扩大其范围,这也有点糟糕。

于 2014-07-22T15:21:45.850 回答
2

我认为这种方法是可以的,只要您的客户只会使用您IOObject做任何事情run,并且不想connect直接调用然后使用file_object打开的 做一些其他操作。

上下文管理器使客户更容易准确地知道他们在哪里获取/清理资源,也让他们可以灵活地用它做任何他们想做的事情,知道一旦他们离开with块,它就会被清理向上。使用这种方法就不太清楚了。客户需要查看代码(或者可能是文档)才能知道该run方法将为他们清理,但如果connect直接使用,cleanup则需要调用以正确清理。

还有 Python 的禅宗规则“显式优于隐式”。该with语句显式地向客户端显示获取和释放资源的位置。你用装饰器方法失去了它。

于 2014-07-22T15:24:38.530 回答