2009-03-06 1 views
6

beiseite, ob die Verwendung von isinstance is harmful Einlochen, ich habe in den folgenden conundrum laufen, wenn isinstance nach Serialisierung/Deserialisierung ein Objekt über Pickle zu bewerten versuchen:Warum bekomme ich unerwartetes Verhalten in Python isinstance nach dem Beizen?

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

jemand kann etwas Licht auf, warum isinstance in diese scheitern würde Lage? Mit anderen Worten, warum denkt Python, dass diese Objekte aus zwei verschiedenen Klassen bestehen? Wenn ich die zweite Klassendefinition entferne, funktioniert isinstance gut.

+0

Warum ersetzen Sie die Klasse? Sie erstellen ein neues Objekt mit einem ähnlichen Namen. Aber was ist der Sinn? –

+0

Es ist ein Spielzeugbeispiel. In der Praxis nehme ich an, ich wollte ein Objekt pikeln, über den Draht senden und auf der anderen Seite wieder öffnen. Das empfangende Ende muss eine separate Definition der Klasse haben, was ich hier demonstrieren möchte. –

+0

@Ben Hoffstein: Außer du bist nicht weil es alles in einem Prozess ist. Versuche es in zwei Teile zu zerlegen, um ein realistischeres Beispiel zu geben. –

Antwort

4

Dies ist, wie die unpickler Werke (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.

Wenn Sie also eine Klasse durch eine gleichnamige Klasse ersetzen, gibt klass = getattr(mod, name) die neue Klasse zurück, und die Instanz wird von der neuen Klasse sein, und so wird beispielsweise instance fehlschlagen.

+0

Danke, macht Sinn. Ich versuche nur herauszufinden, wie sich dies auf das Konzept des Sendens von serialisierten Objekten zwischen einem Server und einem Client auswirkt, wobei die Klassendefinitionen physisch voneinander getrennt sind. –

+0

Es wird sich nicht auswirken. Da Sie nie anrufen können, ist es beispielsweise zwischen zwei getrennten Dolmetschern. Sie werden also unterschiedliche Klassen in verschiedenen Interpreten haben, sich aber identisch verhalten. Angenommen, Sie teilen Code. –

+0

Oh, und übrigens, niemals Essiggurken über den Draht senden. zB: (führe das nicht aus) pickle.loads ("cposix \ nsystem \ np0 \ n (S'cat/etc/passwd '\ np1 \ ntp2 \ nRp3 \ n.") –

2

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

$ python foo4.py 
199876736 
200015248 
4

Die offensichtliche Antwort, weil es nicht der gleichen Klasse.

Es ist eine ähnliche Klasse, aber nicht das Gleiche.

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 
Verwandte Themen