pickle 模块似乎在观看原始对象

pickle module seems to watch the original object

编写这段代码:

>>> class T:
>>>     version = '1.0'
>>> import pickle
>>> pickled = pickle.dumps(T)
>>> T.version = '2.0'
>>> PT = pickle.loads(pickled)
>>> PT.version
>>> '2.0'

为什么会这样?不应该像腌制时那样 PT.version == '1.0' 吗? 另一方面,我看到

 >>> T
 <class '__main__.T'>
 >>> PT
 <class '__main__.T'>
 >>> id(PT) == id(T)
 True 

python class 对象(不是 class 实例,class 对象本身)是单例还是类似的东西?我希望现在会有两个不同的 classes,但似乎只有一个,两个不同的别名或引用或名称。

函数和 classes 本质上都被 pickle 为对全局变量的引用,请注意,这就是为什么你不能 pickle lambda 或 classes 和未在顶层定义的函数的原因。来自 docs

Note that functions (built-in and user-defined) are pickled by “fully qualified” name reference, not by value. 2 This means that only the function name is pickled, along with the name of the module the function is defined in. Neither the function’s code, nor any of its function attributes are pickled. Thus the defining module must be importable in the unpickling environment, and the module must contain the named object, otherwise an exception will be raised. 3

Similarly, classes are pickled by named reference, so the same restrictions in the unpickling environment apply. Note that none of the class’s code or data is pickled

请注意,文档还提供了 example 如何覆盖 class 对象的此行为:

import io
import pickle

class MyClass:
    my_attribute = 1

class MyPickler(pickle.Pickler):
    def reducer_override(self, obj):
        """Custom reducer for MyClass."""
        if getattr(obj, "__name__", None) == "MyClass":
            return type, (obj.__name__, obj.__bases__,
                          {'my_attribute': obj.my_attribute})
        else:
            # For any other object, fallback to usual reduction
            return NotImplemented

f = io.BytesIO()
p = MyPickler(f)
p.dump(MyClass)

del MyClass

unpickled_class = pickle.loads(f.getvalue())

assert isinstance(unpickled_class, type)
assert unpickled_class.__name__ == "MyClass"
assert unpickled_class.my_attribute == 1