Python pickle crash al intentar devolver el valor predeterminado en __getattr__

Tengo un diccionario como clase que utilizo para almacenar algunos valores como atributos. Recientemente agregué algo de lógica ( __getattr__ ) para devolver Ninguno si no existe un atributo. Tan pronto como hice este pickle se estrelló, y quería saber por qué.

Código de prueba:

 import cPickle class DictionaryLike(object): def __init__(self, **kwargs): self.__dict__.update(kwargs) def __iter__(self): return iter(self.__dict__) def __getitem__(self, key): if(self.__dict__.has_key(key)): return self.__dict__[key] else: return None ''' This is the culprit...''' def __getattr__(self, key): print 'Retreiving Value ' , key return self.__getitem__(key) class SomeClass(object): def __init__(self, kwargs={}): self.args = DictionaryLike(**kwargs) someClass = SomeClass() content = cPickle.dumps(someClass,-1) print content 

Resultado:

 Retreiving Value __getnewargs__ Traceback (most recent call last): File <> line 29, in  content = cPickle.dumps(someClass,-1) TypeError: 'NoneType' object is not callable` 

¿Hice algo estúpido? ¿Leí un post que deepcopy () podría requerir que lance una excepción si no existe una clave? Si este es el caso, ¿hay alguna manera fácil de lograr lo que quiero sin lanzar una excepción?

El resultado final es que si algunas llamadas

 someClass.args.i_dont_exist 

Quiero que vuelva ninguno.

Implementar __getattr__ es un poco complicado, ya que se llama para todos los atributos que no existen. En su caso, el módulo pickle prueba su clase para el método especial __getnewargs__ y no recibe None , que obviamente no se puede llamar.

Es posible que desee modificar __getattr__ para llamar a la implementación base para nombres mágicos:

 def __getattr__(self, key): if key.startswith('__') and key.endswith('__'): return super(DictionaryLike, self).__getattr__(key) return self.__getitem__(key) 

Por lo general, paso por todos los nombres que comienzan con un guión bajo, de modo que pueda eludir la magia de los símbolos internos.

Necesita elevar un AttributeError cuando un atributo no está presente en su clase:

 def __getattr__(self, key): i = self.__getitem__(key) if i == None: raise AttributeError return self.__getitem__(key) 

Voy a asumir que este comportamiento es requerido. De la documentación de python para getattr , “Llamado cuando una búsqueda de atributo no ha encontrado el atributo en los lugares habituales (es decir, no es un atributo de instancia ni se encuentra en el árbol de clases para sí mismo). Name es el nombre del atributo. Este método debe devolver el valor del atributo (calculado) o elevar una excepción AttributeError “.

No hay forma de decirle a pickle, etc., que el atributo que está buscando no se encuentra a menos que se produzca la excepción. Por ejemplo, en su mensaje de error, pickle está buscando un método especial llamado __getnewargs__ , pickle espera que si no se encuentra la excepción AttributeError, el valor de retorno sea llamable.

¿Supongo que un posible trabajo a su alrededor podría intentar definir todos los métodos especiales que Pickle está buscando como métodos ficticios?