Warum erhalte ich ein unerwartetes Verhalten in Python isinstance nach dem Beizen?

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

  •  05-07-2019
  •  | 
  •  

Frage

Lässt man einmal beiseite, ob die Verwendung von isinstance schädlich ist, ich habe in den Lauf folgende Rätsels, wenn nach der Serialisierung / Deserialisierung ein Objekt über Pickle zu bewerten isinstance versuchen:

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__)

Kann jemand etwas Licht auf, warum isinstance in dieser Situation scheitern würde? Mit anderen Worten, warum denkt Python diese Objekte sind von zwei verschiedenen Klassen? Wenn ich die zweite Klassendefinition zu entfernen, isinstance funktioniert.

War es hilfreich?

Lösung

Dies ist, wie der unpickler arbeitet (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

zu finden und eine Klasse instanziiert.

So natürlich, wenn Sie eine Klasse mit einer gleichnamigen Klasse ersetzen, die klass = getattr(mod, name) wird die neue Klasse zurückkehrt, und die Instanz der neuen Klasse sein, und so wird isinstance versagen.

Andere Tipps

Die offensichtliche Antwort, weil es nicht die gleiche Klasse.

Es ist eine ähnliche Klasse, aber nicht gleich.

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

Ändern Sie den Code der id von x.__class__ und x2.__class__ zu drucken, und Sie werden sehen, dass sie anders sind:

$ python foo4.py
199876736
200015248
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top