更新子类中的父字典

Update parent dict in subclass

我有 class 个这样的:

class Parent(object):
    _defaults = {
        'key': 'value',
        'key2': 'value',
    }

class Child(Parent):
    _defaults = {
        'key2': 'value2',
        'key3': 'value2',
    }

当我创建子项 class 时,我希望将 _defaults 设置为父项 class _defaults,然后使用子项 _defaults 进行更新.所以实际解析的 class 应该是这样的:

class Child(object):
    _defaults = {
        'key': 'value',
        'key2': 'value2',
        'key3': 'value2',
    }

这可以用 __metaclass__ 构造函数或其他东西实现吗?

您可以使用 collections.ChainMap

import collections

class Child(Parent):
    _defaults = collections.ChainMap({
        'key2': 'value2',
        'key3': 'value2',
    }, Parent._defaults)

当然,您 可以 编写一个元类来为您组合这些东西,但要弄清楚(通常)哪些映射 应该 与超类上的映射相结合并且应该覆盖...

直接读取字典条目,然后更新?

class Parent(object):
    _defaults = {
        'key': 'value',
        'key2': 'value',
    }


class Child(Parent):
    _defaults = {k: v for k, v in Parent._defaults.items()}
    _defaults.update({'key2': 'value2',
                      'key3': 'value2'})


testpar = Parent()
test = Child()

print(testpar._defaults)
print(test._defaults)

打印:

{'key2': 'value', 'key': 'value'}
{'key3': 'value2', 'key2': 'value2', 'key': 'value'}

在 2.7 和 3.5 中

使用 metaclass 您需要在 __new__ 方法中执行此操作,以便在实例化之前应用更改。由于 __new__ 方法接受 cls, name, bases, namespace, **kwds 作为参数,您可以简单地使用 bases 参数访问父对象,该参数是所有基数 classes 的元组,然后您可以简单地更新您的预期属性。

class MyMetaClass(type):

    def __new__(cls, name, bases, namespace, **kwds):
        bases[0]._defaults.update(namespace['_defaults'])
        result = type.__new__(cls, name, bases, dict(namespace))
        return result


class Parent(object):
    _defaults = {
        'key': 'value',
        'key2': 'value',
    }

class Child(Parent, metaclass=MyMetaClass):
    _defaults = {
        'key2': 'value2',
        'key3': 'value2',
    }

演示:

c = Child()    
print(type(c).__bases__[0]._defaults)
{'key2': 'value2', 'key3': 'value2', 'key': 'value'}

请注意,正如@jsbueno 提到的,此方法有一个大问题,即在每次实例化时更新父 class 的 _defaults 属性。拒绝此问题的一种方法可能是为元 class 提供一个标志,以便仅更新父级一次。