2011-09-08 32 views
3

我使用h5py訪問HDF5文件並將h5py File對象存儲在類中。但我經歷試圖重新分配一個新的封閉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'。

+0

如果您註釋掉'self.h5file = newh5file'行,它會打印「關閉」嗎? 'self.h5file' a [屬性](http://docs.python.org/library/functions.html#property)? 'h5py.File()'是否保持一些全局狀態? – jfs

+0

如果我註釋掉'self.h5file = newh5file',有趣的是'newh5file'和'self.h5file'(我明確關閉)顯示爲正在打開''。該示例是獨立的,self.h5file不是屬性。我不能告訴你很多關於'h5py.File()'的實現,如果有一些全局狀態,我不會感到驚訝,但我不明白如何簡單地分配一個實例變量改變全局狀態(某人正在做引用計數的地方?)。 –

回答

1

是的,這是h5py 1.3中的一個已知錯誤,當​​您使用HDF5 1.8.5或更新版本時會顯示此錯誤。它與1.8.5中處理標識符的方式有關。您可以通過使用HDF5 1.8.4或更早版本或者升級到h5py 2.0來修復它。

+0

謝謝,我會嘗試一下,如果你碰巧有一個郵件列表文章或討論這個的bug報告的參考,這將是有幫助的。 –

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__(),這顯然返回False。

所以,你是正確的問題是不與名稱綁定(轉讓),但爲什麼register_thread和/或self.id是轟炸你,我不知道。

+0

這很有趣。我不熟悉__nonzero__,謝謝你的解釋。 –

+0

@大衛沒問題。在Python 3中'__nonzero__'已被重命名爲'__bool__';另外,如果這個方法不存在,則嘗試'__len__'(0 ='False',否則'True');如果'__len__'也不存在,則該類的所有實例都被認爲是「真」。 –