Почему экземпляры этого подкласса set не могут быть выделены? - PullRequest
2 голосов
/ 10 октября 2019

Когда я выкидываю экземпляр класса в файл с модулем pickle, он успешен, однако, когда я загружаю экземпляр из файла, он завершается с ошибкой TypeError.

Я обнаружил, что все подклассы, полученные из набора, будут поднимать TypeError при попытке его раскрыть.

class TreeKeys(set):
    def __init__(self):
        super(TreeKeys, self).__init__()

    def add(self, tk):
        assert tk.__class__ == tuple
        super(TreeKeys, self).add(tk)


if __name__ == '__main__':
    a = TreeKeys()
    a.add((1,2,3))
    with open('tmp.pickle', 'wb') as tmp_fd:
        pickle.dump(a, tmp_fd)
    with open('tmp.pickle', 'rb') as tmp_fd:
        obj = pickle.load(tmp_fd)  # this is the code line raise the TypeError exception.
    pass
Connected to pydev debugger (build 182.3684.100)
Traceback (most recent call last):
  File "C:\Program Files\JetBrains\PyCharm Community Edition 2018.2\helpers\pydev\pydevd.py", line 1664, in <module>
    main()
  File "C:\Program Files\JetBrains\PyCharm Community Edition 2018.2\helpers\pydev\pydevd.py", line 1658, in main
    globals = debugger.run(setup['file'], None, None, is_module)
  File "C:\Program Files\JetBrains\PyCharm Community Edition 2018.2\helpers\pydev\pydevd.py", line 1068, in run
    pydev_imports.execfile(file, globals, locals)  # execute the script
  File "G:/pycharm-projects/new_keyinfo/verify_treekeys.py", line 56, in <module>
    obj = pickle.load(tmp_fd)
  File "C:\Python27_64bit\Lib\pickle.py", line 1384, in load
    return Unpickler(file).load()
  File "C:\Python27_64bit\Lib\pickle.py", line 864, in load
    dispatch[key](self)
  File "C:\Python27_64bit\Lib\pickle.py", line 1139, in load_reduce
    value = func(*args)
TypeError: __init__() takes exactly 1 argument (2 given)

Process finished with exit code -1

1 Ответ

1 голос
/ 10 октября 2019

Проблема в том, что вы не определили метод __init__() вашего класса для принятия (необязательного) итерируемого аргумента, как его базовый класс, встроенный класс set делает, и pickle пытается вызвать его одним из них, чтобы восстановить содержимое экземпляра при загрузке файла.

Вот простой способ исправить это:

import pickle

class TreeKeys(set):
    def __init__(self, iterable=None):
        if iterable is None:
            super(TreeKeys, self).__init__()
        else:
            super(TreeKeys, self).__init__(iterable)

    def add(self, tk):
        assert tk.__class__ == tuple
        super(TreeKeys, self).add(tk)


if __name__ == '__main__':
    a = TreeKeys()
    a.add((1,2,3))
    with open('tmp.pickle', 'wb') as tmp_fd:
        pickle.dump(a, tmp_fd)
    with open('tmp.pickle', 'rb') as tmp_fd:
        obj = pickle.load(tmp_fd)  # This will now work.
    print(obj)  # -> TreeKeys([(1, 2, 3)])
...