Python:可以做一个"deep class override"吗?
Python: Is it possible to do a "deep class override"?
我想创建 dict
的子class,其中包含适用于所有嵌套字典的自定义比较函数。此示例 class 忽略所有在顶层具有键 'j' 的字典值,但在制作副本时不会替换较低级别的字典:
import copy
p = {'a': 1, 'j': 2, 'c': [{'j':'cat','k':'dog'}]}
class udict(dict):
def __init__(self, x):
dict.__init__(self, copy.deepcopy(x))
def __eq__(self, other):
return all([self[k]==other[k] for k in set(self.keys())-set('j')])
a = udict(p)
b = udict(p)
a==b # True
b['j'] = 5
a==b # True - 'j' keys are imaginary and invisible
b['a'] = 5
a==b # False
b = udict(p)
b['c'][0]['j'] = 'bird'
a==b # False (should be True, but list contains dicts, not udicts)
我可以手动树遍历任意深度的数据结构,用一个 udict 替换每个字典,但是如果我无论如何都必须遍历数据结构,我将只在递归中进行比较而不定义自定义 class.
那么有没有一种方法可以定义自定义子class,自动替换基础class的所有嵌入实例?
您可以在您的设备上实施 __deepcopy__
方法
自定义 class: https://docs.python.org/2/library/copy.html -
你将不得不 "use recursion" - 但它仍然认为它比你在那里必须做的任何其他事情都容易:
from copy import deepcopy
def custom_deepcopier(dct, memo=None):
result = MD()
for key, value in dct.items():
if isinstance(value, dict):
result[key] = MD(value)
else:
result[key] = deepcopy(value, memo)
return result
class MD(dict):
def __init__(self, x=None):
if x:
dict.__init__(self, custom_deepcopier(x))
def __eq__(self, other):
...
__deepcopy__ = custom_deepcopier
以这种方式声明时,custom_deepcopier
既用作深度复制您的自定义指令之一时自动调用的 deepcopy
方法,也可以 "bootstraped" 与普通字典,作为独立函数调用。
最后,与您需要的答案没有直接关系,在您的真实代码中,考虑从 collections.UserDict
继承而不是 dict - dict 的本机代码中有一些快捷方式可能会带来糟糕的惊喜在您继承的 classes 中为您服务。 (包括用于 __eq__
的固有递归)
一种更简单的方法不需要复制数据,并且用子类替换所选字典的递归简短、明确且易于理解。子类只覆盖相等性测试,它不需要 __init__
或 __copy__
方法:
class MyDict(dict):
def __eq__(self, other):
return <custom equality test result>
def replaceable(var):
if <dict instance should be replaced by subclass instance>:
return <dict of instances to be replaced>
return {}
def replacedict(var)
if isinstance(var, list):
for i, v in enumerate(var):
var[i] = replacedict(v)
elif isinstance(var, dict):
for k, v in var.items():
var[k] = replacedict(v)
rep = replaceable(var)
for k, v in rep.items():
rep[k] = MyDict(v)
return(var)
对于测试JSON 模式的特定情况,以测试是否可以将多个属性合并到一个模式属性中:
def replaceable(var):
if 'type' in var and var['type'] == 'object' and \
'properties' in var and isinstance(var['properties'],dict):
return var['properties']
return {}
我想创建 dict
的子class,其中包含适用于所有嵌套字典的自定义比较函数。此示例 class 忽略所有在顶层具有键 'j' 的字典值,但在制作副本时不会替换较低级别的字典:
import copy
p = {'a': 1, 'j': 2, 'c': [{'j':'cat','k':'dog'}]}
class udict(dict):
def __init__(self, x):
dict.__init__(self, copy.deepcopy(x))
def __eq__(self, other):
return all([self[k]==other[k] for k in set(self.keys())-set('j')])
a = udict(p)
b = udict(p)
a==b # True
b['j'] = 5
a==b # True - 'j' keys are imaginary and invisible
b['a'] = 5
a==b # False
b = udict(p)
b['c'][0]['j'] = 'bird'
a==b # False (should be True, but list contains dicts, not udicts)
我可以手动树遍历任意深度的数据结构,用一个 udict 替换每个字典,但是如果我无论如何都必须遍历数据结构,我将只在递归中进行比较而不定义自定义 class.
那么有没有一种方法可以定义自定义子class,自动替换基础class的所有嵌入实例?
您可以在您的设备上实施 __deepcopy__
方法
自定义 class: https://docs.python.org/2/library/copy.html -
你将不得不 "use recursion" - 但它仍然认为它比你在那里必须做的任何其他事情都容易:
from copy import deepcopy
def custom_deepcopier(dct, memo=None):
result = MD()
for key, value in dct.items():
if isinstance(value, dict):
result[key] = MD(value)
else:
result[key] = deepcopy(value, memo)
return result
class MD(dict):
def __init__(self, x=None):
if x:
dict.__init__(self, custom_deepcopier(x))
def __eq__(self, other):
...
__deepcopy__ = custom_deepcopier
以这种方式声明时,custom_deepcopier
既用作深度复制您的自定义指令之一时自动调用的 deepcopy
方法,也可以 "bootstraped" 与普通字典,作为独立函数调用。
最后,与您需要的答案没有直接关系,在您的真实代码中,考虑从 collections.UserDict
继承而不是 dict - dict 的本机代码中有一些快捷方式可能会带来糟糕的惊喜在您继承的 classes 中为您服务。 (包括用于 __eq__
的固有递归)
一种更简单的方法不需要复制数据,并且用子类替换所选字典的递归简短、明确且易于理解。子类只覆盖相等性测试,它不需要 __init__
或 __copy__
方法:
class MyDict(dict):
def __eq__(self, other):
return <custom equality test result>
def replaceable(var):
if <dict instance should be replaced by subclass instance>:
return <dict of instances to be replaced>
return {}
def replacedict(var)
if isinstance(var, list):
for i, v in enumerate(var):
var[i] = replacedict(v)
elif isinstance(var, dict):
for k, v in var.items():
var[k] = replacedict(v)
rep = replaceable(var)
for k, v in rep.items():
rep[k] = MyDict(v)
return(var)
对于测试JSON 模式的特定情况,以测试是否可以将多个属性合并到一个模式属性中:
def replaceable(var):
if 'type' in var and var['type'] == 'object' and \
'properties' in var and isinstance(var['properties'],dict):
return var['properties']
return {}