更改 __class__.__bases__ 属性和深度复制 (Python 3)

changing __class__.__bases__ attribute and deepcopy (Python 3)

考虑以下代码片段(希望有足够清晰的注释):

from copy import deepcopy

# Needed to be able to set Container __class__.__bases__ to some custom value
class T:
    pass

class Container(T):
    def __init__(self, x):
        self.x = x

class Consolidate:
    "Class preventing setting of items and attributes"
    def __setattr__(self, key, value):
        raise TypeError("Cannot modify %s of object" % key)

    def __setitem__(self, key, value):
        raise TypeError("Cannot modify %s of object" % key)

def consolidate(obj):
    """
    Don't allow further unintentional modification to the object
    """
    obj.__class__.__bases__ = obj.__class__.__bases__ + (Consolidate,)

state = Container(1)
# deepcopy last item of the state list
theState = deepcopy(state)
# Prevent modifications of the original state
consolidate(state)
# Print some value for the following question
print("bases of theState? %s" % str(theState.__class__.__bases__))
print("ids of the objects: %d %d" % (id(theState), id(state)))

我得到输出:

bases of theState? (<class '__main__.T'>, <class '__main__.Consolidate'>)
ids of the objects: 140148079864408 140148079838488

我想知道为什么 class Consolidate 也是 theState 的基础,因为我认为通过深度复制我只会将它添加到状态列表中的最后一个对象。

我怎样才能达到这样的目标? (防止在深度复制后修改一个对象的属性而不影响复制的对象?)

您更改了class,它在所有实例中共享。复制复制实例的状态,而不是 class 层次结构,因为 classes 不被视为状态,它们被假定保持稳定。

与其改变 class,不如创建第二个 class 并换出要合并的 class 个实例。复制后将新的class赋值给__class__属性即可。

您可以使用 type() function 的 3 参数版本从旧的 class 创建一个新的 class。这也消除了对 T 基础 class 的需要:

class Container:
    def __init__(self, x):
        self.x = x

class Consolidate:
    "Class preventing setting of items and attributes"
    def __setattr__(self, key, value):
        raise TypeError("Cannot modify %s of object" % key)

    def __setitem__(self, key, value):
        raise TypeError("Cannot modify %s of object" % key)

def consolidate(obj):
    # generate a new class object that adds `Consolidated` to the hierarchy.
    cls = type(obj)
    consolidated_class = type(cls.__name__ + 'Consolidated', (Consolidate, cls), {})
    obj.__class__ = consolidated_class