¿Por qué obtengo un comportamiento inesperado en Python es la instancia después del decapado?

Dejando de lado si el uso de isinstance es dañino , me he encontrado con el siguiente enigma al intentar evaluar su instancia después de serializar / deserializar un objeto a través de Pickle:

from __future__ import with_statement import pickle # Simple class definition class myclass(object): def __init__(self, data): self.data = data # Create an instance of the class x = myclass(100) # Pickle the instance to a file with open("c:\\pickletest.dat", "wb") as f: pickle.dump(x, f) # Replace class with exact same definition class myclass(object): def __init__(self, data): self.data = data # Read an object from the pickled file with open("c:\\pickletest.dat", "rb") as f: x2 = pickle.load(f) # The class names appear to match print x.__class__ print x2.__class__ # Uh oh, this fails...(why?) assert isinstance(x2, x.__class__) 

¿Alguien puede arrojar algo de luz sobre por qué la instancia fallaría en esta situación? En otras palabras, ¿por qué Python piensa que estos objetos son de dos clases diferentes? Cuando isinstance definición de segunda clase, isinstance funciona bien.

Así es como funciona el desempaquetador (site-packages / pickle.py):

 def find_class(self, module, name): # Subclasses may override this __import__(module) mod = sys.modules[module] klass = getattr(mod, name) return klass 

Para encontrar y crear una instancia de una clase.

Por supuesto, si reemplaza una clase con una clase con el mismo nombre, klass = getattr(mod, name) devolverá la nueva clase, y la instancia será de la nueva clase, por lo que su instancia fallará.

La respuesta obvia, porque no es la misma clase.

Es una clase similar, pero no la misma.

 class myclass(object): pass x = myclass() class myclass(object): pass y = myclass() assert id(x.__class__) == id(y.__class__) # Will fail, not the same object x.__class__.foo = "bar" assert y.__class__.foo == "bar" # will raise AttributeError 

Cambie su código para imprimir el id de x.__class__ y x2.__class__ y verá que son diferentes:

 $ python foo4.py 199876736 200015248