更改__class __.__ bases__属性和Deepcopy(Python 3)

时间:2018-08-11 21:47:39

标签: python-3.x class deep-copy

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

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

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

我如何达到这样的目标? (防止在对一个对象进行深度复制之后修改其属性,而又不影响复制的对象吗?)

1 个答案:

答案 0 :(得分:0)

您更改了,该类在所有实例之间都是共享。复制会复制实例的状态,而不是类的层次结构,因为类不会被视为状态,因此假定它们保持稳定。

创建一个 second class 并替换您要合并的实例的类,而不是更改该类。复制后,只需将新类分配给__class__属性即可。

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

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