设计描述文件的python pickleable对象

时间:2010-11-05 20:36:12

标签: python pickle

我想创建一个描述文件资源的类,然后选择它。这部分很简单。具体来说,假设我有一个类“A”,它具有对文件进行操作的方法。如果它不包含文件句柄,我可以pickle这个对象。我希望能够创建文件句柄以访问“A”描述的资源。如果我在类“A”中有一个“open()”方法打开并存储文件句柄供以后使用,那么“A”不再是pickleable。 (我在这里添加打开文件包括一些不能缓存的非平凡索引 - 第三方代码 - 因此在需要时关闭和重新打开并非没有费用)。我可以将类“A”编码为可以为所描述的文件生成文件句柄的工厂,但这可能导致多个文件句柄同时访问文件内容。我可以使用另一个类“B”来处理类“A”中文件的打开,包括锁定等。我可能会过度思考这个,但任何提示都会受到赞赏。

3 个答案:

答案 0 :(得分:6)

问题不太清楚;它看起来像是:

  • 您有第三方模块,其中包含可选类
  • 这些类可能包含对文件的引用,这使得这些类本身不可选择,因为打开的文件不可选择。

基本上,您希望将可打开的文件设为可选。你可以相当容易地做到这一点,但有一些警告。这是一个不完整但功能齐全的样本:

import pickle
class PicklableFile(object):
    def __init__(self, fileobj):
        self.fileobj = fileobj

    def __getattr__(self, key):
        return getattr(self.fileobj, key)

    def __getstate__(self):
        ret = self.__dict__.copy()
        ret['_file_name'] = self.fileobj.name
        ret['_file_mode'] = self.fileobj.mode
        ret['_file_pos'] = self.fileobj.tell()
        del ret['fileobj']
        return ret

    def __setstate__(self, dict):
        self.fileobj = open(dict['_file_name'], dict['_file_mode'])
        self.fileobj.seek(dict['_file_pos'])
        del dict['_file_name']
        del dict['_file_mode']
        del dict['_file_pos']
        self.__dict__.update(dict)

f = PicklableFile(open("/tmp/blah"))
print f.readline()
data = pickle.dumps(f)
f2 = pickle.loads(data)
print f2.read()

注意事项和注释,有些是明显的,有些则不那么:

  • 此类应直接对从open获取的文件对象进行操作。如果您在文件上使用包装类,例如gzip.GzipFile,则应该高于此值,而不是低于此值。从逻辑上讲,将其视为file上的装饰者类。
  • 如果你在unpickle时文件不存在,它就不会被打开并且会抛出异常。
  • 如果是不同的文件,行为可能有意义也可能没有意义。
  • 如果文件模式包含文件创建('w +'),并且文件不存在,则会创建;我们不知道要使用哪些文件权限,因为它不与文件一起存储。如果这很重要 - 它可能不应该 - 然后在您第一次创建时在类中存储正确的权限。
  • 如果文件不可搜索,尝试查找旧位置可能会引发IOError;如果您使用的是这样的文件,则需要决定如何处理。
  • Python 2和Python 3中的文件类不同; Python 3中没有file类。即使你现在只使用Python 2,也不要继承file

我不会这样做;腌制数据取决于外部文件不变化和停留在同一个地方是脆弱的。这使得甚至难以重新定位文件,因为你的腌制数据没有意义。

答案 1 :(得分:1)

如果你打开一个指向文件的指针,腌制它,然后再尝试重新构建,则无法保证文件仍可用于打开。

详细说明,文件指针实际上代表了与文件的连接。就像数据库连接一样,你不能“腌制”连接的另一端,所以这不起作用。

是否可以在自己的进程中将文件指针保留在内存中?

答案 2 :(得分:1)

听起来你知道你不能腌制手柄,而你没关系,你只想腌制可以腌制的部分。正如你的对象现在所说,它不能被腌制,因为它有手柄。我有这个权利吗?如果是这样,请继续阅读。

对于这些情况,pickle模块将让你的类描述自己的pickle状态。您想要定义自己的__getstate__方法。 pickler将调用它来获取要被pickle的状态,只有当方法丢失时才会继续并且做默认的尝试pickle所有属性。