Непонятное поведение присваивания с объектом 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 бомбит на тебя, я не знаю.

Другие вопросы по тегам