更新子类中的父字典
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 提供一个标志,以便仅更新父级一次。
我有 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 提供一个标志,以便仅更新父级一次。