最后尝试使用decorator清理python对象

最后尝试使用decorator清理python对象,python,class,python-2.7,decorator,resource-cleanup,Python,Class,Python 2.7,Decorator,Resource Cleanup,对象清理似乎是我在编程期间遇到的一个非常常见的问题。迄今为止,我一直按照建议将与语句一起使用 今天我有另一个想法,对我来说似乎更优雅(因为它不需要最终用户的with语句)。其想法是对特定类型的对象使用try-finally装饰器(具有清理方法) 只是想知道这种做法是否有问题,或者是否有更好的地方。我不喜欢我的许多类需要使用with语句初始化,但我还希望确保我的对象正确关闭。这里有一个简短的例子 def cleanme(func): def _decorator(self, *args,

对象清理似乎是我在编程期间遇到的一个非常常见的问题。迄今为止,我一直按照建议将
语句一起使用

今天我有另一个想法,对我来说似乎更优雅(因为它不需要最终用户的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

让我在这上面打几个洞

一种想法是,您强制您的类拥有一个
cleanup()
,它声明在与
run()
不同的位置。因此,您要求用户负责干净地实现和维护它

Python中除了
\uuuu exit\uuuu
之外的析构函数非常少见,因此资源获取代码可能会从
cleanup()
代码中漂移,从而造成泄漏


其次,您正在将
file\u object
作为一个实例变量,从而将其范围从单个函数扩展到另一个函数,这也有点不好。

我认为这种方法是可以的,只要您的客户机只使用
IOObject
来执行
run
所做的任何操作,并且不希望直接调用
connect
,然后使用打开的
file\u对象执行其他操作

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


还有Python的禅宗规则“explicit优于Implicit”。
with
语句显式显示正在获取和释放资源的客户端。“with”的意义在于摆脱这种“以后清理一切”的想法,明确说明您使用的资源。您应该将对象分为两部分,一部分是资源(保存该文件对象并知道如何清理),另一部分是使用它的,“run”方法应该是“with my_resources:while:do_stuff()”。这在使用许多IO样式的对象时会变得非常混乱(假设我有3个打开的套接字来接收数据、一个视频馈送对象和一些通信管道等)。相反,我可以有一个连接方法和一个关闭方法来处理每一个。我想这可以解决这个问题: