h5py对象作为实例变量时的困惑赋值行为

3 投票
2 回答
655 浏览
提问于 2025-04-17 01:51

我正在使用h5py来访问HDF5文件,并把h5py的文件对象存储在一个类里。但是在尝试用一个新的文件对象替换一个已经关闭的h5py文件实例时,遇到了一些奇怪的情况:

class MyClass:
    def __init__(self, filename):
        self.h5file = None
        self.filename = filename

    def vartest(self):
        self.h5file = h5py.File(self.filename, 'r')
        print self.h5file
        self.h5file.close()
        print self.h5file
        newh5file = h5py.File(self.filename, 'r')
        print newh5file
        self.h5file = newh5file
        print self.h5file
        print newh5file

def main():
    filename = sys.argv[1]
    mycls = MyClass(filename)
    mycls.vartest()

输出结果:

<HDF5 file "test.h5" (mode r, 92.7M)>
<Closed HDF5 file>
<HDF5 file "test.h5" (mode r, 92.7M)>
<Closed HDF5 file>
<Closed HDF5 file>

当我尝试用新打开的h5py文件对象更新实例变量时,似乎影响了这个对象的状态,导致它被关闭了。无论h5py的实现是什么,我觉得这种行为在我理解的Python语言中是没有道理的(也就是说,赋值操作符并没有被重载)。

这个例子是在Python 2.6.5和h5py 1.3.0下运行的。如果你想试试这个例子,但手头没有HDF5文件,可以把文件访问模式从'r'改成'a'。

2 个回答

1

不确定这是否有帮助,但我在源代码中找到了一些东西(简化版):

class HLObject(object):
    def __nonzero__(self):
        register_thread()
        return self.id.__nonzero__()

class Group(HLObject, _DictCompat):
    ...

class File(Group):
    def __repr__(self):
        register_thread()
        if not self:
            return "<Closed HDF5 file>"
        return '<HDF5 file "%s" (mode %s, %s)>' % \
            (os.path.basename(self.filename), self.mode,
             _extras.sizestring(self.fid.get_filesize()))

因为没有定义 __str__ 方法,所以会调用 __repr__ 方法来生成输出。__repr__ 方法首先会调用 register_thread(),然后检查 self 是否存活(简单来说,就是判断它是“真”还是“假”)。

接着,Python 会在类中查找,直到找到 __nonzero__(这个方法也会调用 register_thread()),然后返回 self.id.__nonzero__(),结果显然是返回了“假”。

所以,你说得对,问题不在于名字绑定(赋值),但为什么 register_thread 和/或 self.id 出现了错误,我就不知道了。

1

没错,这是h5py 1.3中的一个已知问题,当你使用HDF5 1.8.5或更新版本时就会出现这个问题。这个问题和1.8.5版本中对标识符处理方式的变化有关。你可以通过使用HDF5 1.8.4或更早的版本来解决这个问题,或者升级到h5py 2.0版本。

撰写回答