Непонятное поведение присваивания с объектом h5py в качестве переменной экземпляра
Я использую h5py для доступа к файлам HDF5 и хранения объектов 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 объекта File, похоже, как-то повлияла на состояние объекта, закрыв его. Независимо от реализации на стороне h5py, я не вижу, как это поведение имеет смысл из моего понимания языка Python (то есть, без перегрузки оператора присваивания).
Этот пример запускается с Python 2.6.5 и h5py 1.3.0. Если вы хотите попробовать этот пример, но у вас нет файла HDF5, вы можете просто изменить режим доступа к файлу с 'r' на 'a'.
2 ответа
Да, это известная ошибка в h5py 1.3, которая появляется, когда вы используете HDF5 1.8.5 или новее. Это связано с изменениями в способах обработки идентификаторов в 1.8.5. Вы можете исправить это, используя HDF5 1.8.4 или более раннюю версию, или обновив h5py 2.0.
Не уверен, поможет ли это, но при поиске в исходном коде я нашел это (сокращенно):
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
бомбит на тебя, я не знаю.