2010-01-12 21 views
14

tengo una clase (abajo):¿Por qué no puedo eliminar este objeto?

class InstrumentChange(object): 
    '''This class acts as the DTO object to send instrument change information from the 
     client to the server. See InstrumentChangeTransport below 
    ''' 
    def __init__(self, **kwargs): 
     self.kwargs = kwargs 
     self._changed = None 

    def _method_name(self, text): 
     return text.replace(' ','_').lower() 

    def _what_changed(self): 
     ''' Denotes the column that changed on the instrument returning the column_name of what changed.''' 
     if not self._changed: 
      self._changed = self._method_name(self.kwargs.pop('What Changed')) 

     return self._changed 

    def __getattr__(self, attr): 
     for key in self.kwargs.iterkeys(): 
      if self._method_name(key) == attr: 
       return self.kwargs[key] 

    def __str__(self): 
     return "Instrument:%s" % self.kwargs 

    __repr__ = __str__ 

    what_changed = property(_what_changed) 

Cuando ejecuto la siguiente prueba:

def test_that_instrumentchangetransport_is_picklable(self): 
     test_dict = {'Updated': 'PAllum', 'Description': 'BR/EUR/BRAZIL/11%/26/06/2017/BD', 
     'Ask Q': 500, 'Bbg': 'On', 'C Bid': 72.0, 'Benchmark': 'NL/USD/KKB/7.000%/03/11/2009/BD', 
     'ISIN': 'XS0077157575', 'Bid YTM': 0.0, 'Bid Q': 100, 'C Ask': 72.25, 'Ask YTM': 0.0, 'Bid ASW': 0.0, 
     'Position': 1280000, 'What Changed': 'C Bid', 'Ask ASW': 0.0} 
     ins_change = InstrumentChangeTransport(**test_dict) 
     assert isinstance(ins_change, InstrumentChangeTransport) 

     # Create a mock filesystem object 
     file = open('testpickle.dat', 'w') 
     file = Mock() 
     pickle.dump(ins_change, file) 

me sale:

Traceback (most recent call last): 
    File "c:\python23\lib\site-packages\nose-0.11.0-py2.3.egg\nose\case.py", line 183, in runTest 
    self.test(*self.arg) 
    File "C:\Code\branches\demo\tests\test_framework.py", line 142, in test_that_instrumentchangetransport_is_picklable 
    pickle.dump(ins_change, file) 
    File "C:\Python23\Lib\copy_reg.py", line 83, in _reduce_ex 
    dict = getstate() 
TypeError: 'NoneType' object is not callable 

He mirado en los documentos de la salmuera, pero no lo entiendo del todo

¿Alguna idea?

Ben

+1

Como nota al margen: 'key in self.kwargs.iterkeys()' genera una lista de claves y las busca a través de ellas. Mejor uso 'clave en self.kwargs', que intenta hacer una búsqueda hashtable (más rápido). – ebo

+1

Al pedir ayuda para depurar algo, es útil proporcionar el código suficiente para reproducir el problema. Ayuda aún más eliminar todo lo irrelevante del código que publica. –

Respuesta

29

Su código tiene varias cuestiones secundarias "laterales": la aparición repentina de un 'Transporte' en el nombre de clase utilizado en la prueba (no es el nombre de clase que está definiendo), el dudoso pisoteo sobre el built-in identificador file como una variable local (no haga eso, no duele aquí, pero el hábito de pisotear identificadores incorporados causará errores misteriosos un día), los usos indebidos de Mock que ya se han observado, el uso predeterminado del protocolo y texto de decapado más lento y sucio en lugar de binario para el archivo de pickle.

Sin embargo, en el fondo, como dice @coonj, es la falta de control del estado. Una clase "normal" no la necesita (porque self.__dict__ se escabea y se deshace por defecto en las clases que carecen de control de estado y sin otras peculiaridades), pero ya que está anulando __getattr__ que no se aplica a su clase. Sólo necesita dos más métodos muy sencillos:

def __getstate__(self): return self.__dict__ 
def __setstate__(self, d): self.__dict__.update(d) 

que básicamente dice pickle para tratar su clase al igual que una normal, teniendo self.__dict__ como la representación de la totalidad del estado de la instancia, a pesar de la existencia de la __getattr__.

+0

Gracias por validar esto - más de 100 visitas y usted es el primero en estar de acuerdo conmigo ...Me estaba preocupando –

+4

@coonj, supongo que las personas tienen dificultades para ver por qué uno debería necesitar definir los métodos de manejo del estado ya que normalmente no son necesarios (y en ninguna parte está claramente documentado que '__getattr__' los hace necesarios). –

+0

Gracias Alex & coonj, Esta prueba fue para recrear un problema que estaba teniendo con el envío de un objeto remoto sobre una sesión retorcida de pb. Es un poco complicado, pero realmente aprecio tus puntos. Mi aprendizaje de Python acaba de marcar unos pocos clics. Gracias de nuevo por su ayuda. Ben –

2
file = open('testpickle.dat', 'w') 
    file = Mock() 

que está perdiendo aquí referencia al archivo abierto. ¿Podría ser eso un problema?

+0

Esta parece ser la causa probable del problema. – jathanism

6

Está fallando porque no puede encontrar __getstate__() para su objeto. Pickle necesita estos para determinar cómo desenterrar/desengrasar el objeto. Solo necesita los métodos __getstate__() y __setstate__().

Véase el ejemplo TextReader en la documentación: http://docs.python.org/library/pickle.html

actualización: Yo miraba a la sourceforge page for the Mock module, y creo que también está usando de manera incorrecta. Se está burlando de un archivo-objeto, pero cuando pickle intenta leer de él, no obtendrá nada, razón por la cual getattr() no devuelve ninguno.

Cuestiones relacionadas