【问题标题】:Why do I get unexpected behavior in Python isinstance after pickling?为什么我在酸洗后在 Python isinstance 中出现意外行为?
【发布时间】:2009-03-06 23:17:27
【问题描述】:

抛开是否使用isinstance is harmful 不谈,在通过Pickle 序列化/反序列化对象后尝试评估isinstance 时,我遇到了以下难题:

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 在这种情况下会失败?换句话说,为什么 Python 认为这些对象属于两个不同的类?当我删除第二个类定义时,isinstance 工作正常。

【问题讨论】:

  • 你为什么要换班?您正在创建一个具有相似名称的新对象。但是有什么意义呢?
  • 这是一个玩具示例。在实践中,假设我想腌制一个对象,将其通过电线发送,然后在另一侧将其解开。接收端需要有一个单独的类定义,这就是我要在这里演示的。
  • @Ben Hoffstein:除了你不是,因为这一切都在一个过程中。试着把它分成两部分来做一个更真实的例子。
  • 感谢所有有用的答案。我以前没有使用过 isinstance,现在对它的工作原理有了更好的了解。

标签: python pickle


【解决方案1】:

这就是 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

查找并实例化一个类。

当然,如果你用同名类替换一个类,klass = getattr(mod, name) 将返回新类,实例将属于新类,因此 isinstance 将失败。

【讨论】:

  • 谢谢,有道理。只是想弄清楚这如何影响在服务器和客户端之间发送序列化对象的概念,其中类定义在物理上是不同的。
  • 它不会影响它。因为你永远不能在两个独立的解释器之间调用 isinstance 。因此它们将是不同解释器中的不同类,但行为相同。假设您正在共享代码。
  • 哦,顺便说一句,永远不要通过电线发送泡菜。例如:(不要运行这个)pickle.loads("cposix\nsystem\np0\n(S'cat /etc/passwd'\np1\ntp2\nRp3\n.")
  • 在互不信任的进程之间通过网络发送泡菜是可以的。例如,在概念上相同的 Web 服务器的两个部分之间是完全合理的。
【解决方案2】:

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

它是一个相似的类,但不一样。

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】:

    更改您的代码以打印x.__class__x2.__class__id,您会发现它们是不同的:

    $ python foo4.py
    199876736
    200015248
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-20
      • 2022-08-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多