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

3

我正在使用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”。

如果您将self.h5file = newh5file代码行注释掉,它是否会打印“closed”? self.h5file是一个property吗? h5py.File() 保持一些全局状态吗? - jfs
如果我注释掉 self.h5file = newh5file,有趣的是,newh5fileself.h5file(我明确关闭了)都显示为打开 <HDF5 file "test.h5" (mode r, 800 bytes)>。这个例子是自包含的,self.h5file 不是一个属性。我不能告诉你太多关于 h5py.File() 的实现,我不会感到惊讶如果有一些全局状态,但我不理解如何简单地分配一个实例变量就改变了那个全局状态(某处正在进行引用计数吗?)。 - David Eklund
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是否存活(更好地称为评估为True或False)。
Python然后搜索类,直到找到__nonzero__(再次调用register_thread()),然后返回self.id.__nonzero__(),显然返回False。
所以,你是正确的,问题不在于名称绑定(赋值),而是为什么register_thread和/或self.id出现错误,我不知道。

很有趣。我之前不熟悉__nonzero__,感谢您的解释。 - David Eklund
@David 没问题。在Python 3中,__nonzero__已被重命名为__bool__;此外,如果该方法不存在,则尝试使用__len__(0 = False,否则为True);如果__len__也不存在,则认为该类的所有实例都为True - Ethan Furman

1

是的,这是 h5py 1.3 中已知的一个 bug,在使用 HDF5 1.8.5 或更新版本时会出现。它与在 1.8.5 中处理标识符的方式有关。您可以通过使用 HDF5 1.8.4 或更早版本来修复它,或者升级到 h5py 2.0。


谢谢,我会尝试一下。如果你恰好有讨论这个问题的邮件列表帖子或错误报告的参考资料,那将非常有帮助。 - David Eklund

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接