Рассечение объекта с помощью метода __getattr__ в Python возвращает `TypeError, объект не может быть вызван`

1

Я хотел бы определить класс, который возвращает None для неизвестных атрибутов с __getattr__ метода __getattr__.

После этого я пытаюсь сбросить объект этого класса в Pickle.

Однако я получил ошибку

Traceback (most recent call last):
  File "c:\SVN\Scripts\Rally\examples\t_pickle_None.py", line 14, in <module>
    pickle.dump(toto, f, pickle.HIGHEST_PROTOCOL)
TypeError: 'NoneType' object is not callable

Без определения __getattr__ он работает нормально, но я хотел бы сохранить эту функцию.

Вот мой код: как заставить его работать с __getattr__?

Спасибо

import pickle
from typing import Any

class Toto:
    def __init__(self, name:str) -> None:
        self.name = name

    def __getattr__(self, _: str) -> Any:
        """Return None for all unknown attributes"""
        return None

toto = Toto("Toto")
with open('toto.pkl', 'wb') as f:
    pickle.dump(toto, f, pickle.HIGHEST_PROTOCOL)
Теги:
python-3.x
pickle

2 ответа

2
Лучший ответ

Проблема в том, что pickle пытается проверить, есть ли у вашего объекта метод __getstate__, который можно использовать для настройки того, как объекты маринуются. Поскольку ваш класс не определяет метод __getstate__, ваш метод __getattr__ и возвращает None. Pickle пытается назвать это значение None и это создает исключение, которое вы получили.

Есть два способа исправить это:

  1. Определите __getstate__ и соответствующий метод __setstate__ в своем классе:

    def __getstate__(self):
        return vars(self)
    
    def __setstate__(self, state):
        vars(self).update(state)
    
  2. Перепишите свой метод __getattr__ чтобы лучше обрабатывать атрибуты dunder (т.е. Выбрасывать AttributeError вместо того, чтобы возвращать бессмысленное значение):

    def __getattr__(self, attr: str) -> Any:
        """Return None for all unknown attributes"""
        if attr.startswith('__') and attr.endswith('__'):
            raise AttributeError
        return None
    
0

Если вы переопределите __getattr__, вы сообщите, как именно ваш объект может быть маринован путем реализации методов __getstate__ и __setstate__

Посмотрите здесь, чтобы узнать больше

>>> import pickle
>>> class Toto:
...     def __init__(self, name:str):
...         self.name = name
...     def __getattr__(self, _: str):
...         """Return None for all unknown attributes"""
...         return None
...     def __getstate__(self): return self.__dict__
...     def __setstate__(self, d): self.__dict__.update(d)
... 
>>> 
>>> t=Toto()
>>> pickle.dumps(t)
b'\x80\x03c__main__\nToto\nq\x00)\x81q\x01}q\x02X\x04\x00\x00\x00nameq\x03X\x03\x00\x00\x00abcq\x04sb.'
>>> 

Ещё вопросы

Сообщество Overcoder
Наверх
Меню