Por que recebo um comportamento inesperado no Python isinstance após decapagem?

StackOverflow https://stackoverflow.com/questions/620844

  •  05-07-2019
  •  | 
  •  

Pergunta

Pondo de lado se o uso de isinstance é prejudicial, eu tenho que correr para o seguinte dilema quando se tenta avaliar isinstance depois de serialização / desserialização de um objeto via 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__)

Alguém pode lançar alguma luz sobre por que isinstance iria falhar nesta situação? Em outras palavras, por que Python acho que esses objetos são de duas classes diferentes? Quando eu remover a segunda definição de classe, isinstance funciona bem.

Foi útil?

Solução

Esta é a forma como as obras unpickler (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 e instanciar uma classe.

Então é claro que se você substituir uma classe com uma classe de nome idêntico, o klass = getattr(mod, name) voltará a nova classe, ea instância será da nova classe, e assim isinstance irá falhar.

Outras dicas

A resposta óbvia, porque não é da mesma classe.

Seu uma classe semelhante, mas não o mesmo.

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

Alterar o código para imprimir o id de x.__class__ e x2.__class__ e você verá que eles são diferentes:

$ python foo4.py
199876736
200015248
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top