لماذا أحصل على سلوك غير متوقع في بيثون isinstance بعد التخليل؟

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

  •  05-07-2019
  •  | 
  •  

سؤال

وإذا وضعنا جانبا ما إذا كان استخدام هو ضار ، لقد واجه في isinstance بعد لغز عند محاولة تقييم isinstance بعد تسلسل / deserializing كائن عبر مخلل:

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

ويمكن لأي شخص أن يلقي بعض الضوء على سبب isinstance ستفشل في هذه الحالة؟ وبعبارة أخرى، لماذا لا بيثون أعتقد أن هذه الكائنات هي من فئتين مختلفتين؟ عندما إزالة تعريف الفئة الثانية، isinstance يعمل بشكل جيد.

هل كانت مفيدة؟

المحلول

وهذه هي الطريقة التي يعمل بها unpickler (حزم الموقع / pickle.py):

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

لايجاد ومثيل فئة.

وذلك بالطبع إذا قمت باستبدال فئة مع فئة المسمى مماثل، فإن klass = getattr(mod, name) إرجاع طبقة جديدة، وسوف يكون المثال للطبقة جديدة، وهكذا isinstance ستفشل.

نصائح أخرى

والجواب واضح، وذلك لأن ليس لها نفس الفئة.

عن فئة مماثلة، ولكن ليست هي نفسها.

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

تغيير التعليمات البرمجية لطباعة id من x.__class__ وx2.__class__ وسترى أنهم مختلفون:

$ python foo4.py
199876736
200015248
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top