具有自定义元 class 的 class 的所有子 class 都共享相同的属性,即使它们不应该

All subclasses of a class with a custom metaclass share the same attributes even though they shouldn't

我定义了一个元class MyMeta 和一个名为MyAttributeType 的自定义属性。然后我创建了 4 个 classes,第一个 class MyObjectA 的 metaclass 属性设置为 MyMeta,class MyObjectB 继承自 MyObjectA 并具有一些属性,然后 MyObjectCMyObjectD 都继承自 MyObjectB 并且它们都具有一些额外的属性。

在 metaclass 中,我将这些属性添加到一个列表中,所以我希望该列表只包含 class 本身及其父项的属性,而不是它们都得到所有属性。

我认为查看代码更容易,下面是一个最小测试,您可以复制并 运行 它应该可以工作。远低于输出与预期输出。

class MyAttributeType(object):

    def __init__(self, name=None, node=None):
        self._name = name
        self._node = node

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, value):
        self._name = value

    @property
    def node(self):
        return self._node

    @node.setter
    def node(self, value):
        self._node = value


class MyMeta(type):

    def __new__(mcs, clsname, clsbases, clsattributes):
        result_dict = {"_attributes": []}

        for base in clsbases:
            try:
                for key, value in base.__dict__.items():
                    if isinstance(value, property) or isinstance(value, MyAttributeType):
                        result_dict[key] = value
                result_dict["_attributes"] = base.__dict__["_attributes"]
            except KeyError:
                pass

        for key, value in clsattributes.items():
            if isinstance(value, MyAttributeType):

                if key.startswith("_"):
                     key = key[1:]

                result_dict["_{0}".format(key)] = value
                result_dict["_attributes"].append(value)

                value.name = key

                result_dict[key] = value

            else:
                result_dict[key] = value

        inst = super(MyMeta, mcs).__new__(mcs, clsname, clsbases, result_dict)
        return inst


class MyObjectA(object):

    __metaclass__ = MyMeta

    _name = None
    _attributes = []

    def __init__(self, name):
        self._name = name

        for attr in self._attributes:
            attr.node = self._name

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, value):
        self._name = value

    @property
    def attributes(self):
        return [attr.name for attr in self._attributes]


class MyObjectB(MyObjectA):

    attr1 = MyAttributeType()
    attr2 = MyAttributeType()
    attr3 = MyAttributeType()


class MyObjectC(MyObjectB):

    attr4 = MyAttributeType()
    attr5 = MyAttributeType()
    attr6 = MyAttributeType()


class MyObjectD(MyObjectB):

    attr7 = MyAttributeType()
    attr8 = MyAttributeType()
    attr9 = MyAttributeType()


a = MyObjectA("testA")
b = MyObjectB("testB")
c = MyObjectC("testC")
d = MyObjectD("testD")

print a.attributes
print b.attributes
print c.attributes
print d.attributes

输出:

['attr2', 'attr3', 'attr1', 'attr6', 'attr5', 'attr4', 'attr7', 'attr8', 'attr9']
['attr2', 'attr3', 'attr1', 'attr6', 'attr5', 'attr4', 'attr7', 'attr8', 'attr9']
['attr2', 'attr3', 'attr1', 'attr6', 'attr5', 'attr4', 'attr7', 'attr8', 'attr9']
['attr2', 'attr3', 'attr1', 'attr6', 'attr5', 'attr4', 'attr7', 'attr8', 'attr9']

预计:

[]
['attr2', 'attr3', 'attr1']
['attr2', 'attr3', 'attr1', 'attr6', 'attr5', 'attr4']
['attr2', 'attr3', 'attr1', 'attr7', 'attr8', 'attr9']

您需要分享基础 类 的 _attributes 作为 副本:

            result_dict["_attributes"] = base.__dict__["_attributes"][:]

共享列表而不复制它意味着更改对所有引用可见。您目前正在执行与此等效的操作:

>>> base_attributes = [] 
>>> child_attributes = base_attributes
>>> child_attributes.append(2)
>>> base_attributes
[2]

使用[:]创建赋值时所有元素的副本:

>>> base_attributes = [] 
>>> child_attributes = base_attributes[:]
>>> child_attributes.append(2)
>>> base_attributes
[]