代码之家  ›  专栏  ›  技术社区  ›  Ben Hoffstein

为什么在酸洗后Python isinstance中会出现意外行为?

  •  7
  • Ben Hoffstein  · 技术社区  · 17 年前

    搁置是否使用 isinstance is harmful

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

    有人能解释一下为什么iInstance会在这种情况下失败吗?换句话说,为什么Python认为这些对象属于两个不同的类?当我删除第二个类定义时, isinstance 很好。

    3 回复  |  直到 17 年前
        1
  •  5
  •   Ali Afshar    17 年前

    这就是取消pickler的工作方式(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
    

    查找并实例化一个类。

    当然,如果用同名类替换一个类 klass = getattr(mod, name)

        2
  •  4
  •   mthurlin    17 年前

    答案显而易见,因为它不是同一类。

    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
    
        3
  •  2
  •   Jacob Gabrielson    17 年前

    更改您的代码以打印 id 属于 x.__class__ 和 x2.__class__ 你会发现它们是不同的:

    $ python foo4.py
    199876736
    200015248