Я хотел бы определить класс, который возвращает 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)
Проблема в том, что pickle пытается проверить, есть ли у вашего объекта метод __getstate__
, который можно использовать для настройки того, как объекты маринуются. Поскольку ваш класс не определяет метод __getstate__
, ваш метод __getattr__
и возвращает None
. Pickle пытается назвать это значение None
и это создает исключение, которое вы получили.
Есть два способа исправить это:
Определите __getstate__
и соответствующий метод __setstate__
в своем классе:
def __getstate__(self):
return vars(self)
def __setstate__(self, state):
vars(self).update(state)
Перепишите свой метод __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
Если вы переопределите __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.'
>>>