避免子类化内置类型。当你发现你的对象由于某种未知原因改变了类型时,你会后悔的。改用委托。例如:
import operator as op
class FuzzyDict(object):
    def __init__(self, iterable=(), float_eq=op.eq):
        self._float_eq = float_eq
        self._dict = dict(iterable)
    def __getitem__(self, key):
        return self._dict[key]
    def __setitem__(self, key, val):
        self._dict[key] = val
    def __iter__(self):
        return iter(self._dict)
    def __len__(self):
        return len(self._dict)
    def __contains__(self, key):
        return key in self._dict
    def __eq__(self, other):
        def compare(a, b):
            if isinstance(a, float) and isinstance(b, float):
                return self._float_eq(a, b)
            else:
                return a == b
        try:
            if len(self) != len(other):
                return False
            for key in self:
                if not compare(self[key], other[key]):
                    return False
            return True
        except Exception:
            return False
    def __getattr__(self, attr):
        # free features borrowed from dict
        attr_val = getattr(self._dict, attr)
        if callable(attr_val):
            def wrapper(*args, **kwargs):
                result = attr_val(*args, **kwargs)
                if isinstance(result, dict):
                    return FuzzyDict(result, self._float_eq)
                return result
            return wrapper
        return attr_val
以及一个示例用法:
>>> def float_eq(a, b):
...     return abs(a - b) < 0.01
... 
>>> A = FuzzyDict(float_eq=float_eq)
>>> B = FuzzyDict(float_eq=float_eq)
>>> A['a'] = 2.345
>>> A['b'] = 'a string'
>>> B['a'] = 2.345
>>> B['b'] = 'a string'
>>> B['a'] = 2.3445
>>> A == B
True
>>> B['a'] = 234.55
>>> A == B
False
>>> B['a'] = 2.345
>>> B['b'] = 'a strin'
>>> A == B
False
即使嵌套它们也可以工作:
>>> A['nested'] = FuzzyDict(float_eq=float_eq)
>>> A['nested']['a'] = 17.32
>>> B['nested'] = FuzzyDict(float_eq=float_eq)
>>> B['nested']['a'] = 17.321
>>> B['b'] = 'a string'   # changed before
>>> A == B
True
>>> B['nested']['a'] = 17.34
>>> A == B
False
一个完整的替代品dict需要更多的代码,并且可能需要一些测试来看看它有多健壮,但即使是上述解决方案也提供了许多dict功能(例如copy,、、setdefault等get)update
关于为什么你不应该继承一个内置的。
这个解决方案看起来简单而正确,但通常并非如此。首先,即使您可以对内置类型进行子类化,但这并不意味着它们被编写为用作子类,因此您可能会发现要使某些东西起作用,您必须编写比您想象的更多的代码。
此外,您可能希望使用内置方法,但这些方法将返回内置类型的实例而不是您的类的实例,这意味着您必须重新实现该类型的每个方法。此外,您有时必须实现内置未实现的其他方法。
例如,子类化list你可能会这样认为,因为list只实现了__iadd__,__add__你可以安全地重新实现这两个方法,但你错了!您还必须实现__radd__,否则表达式如下:
[1,2,3] + MyList([1,2,3])
将返回正常list而不是MyList.
总而言之,子类化一个内置函数比你一开始想的要多得多,并且由于类型或行为的变化,它可能会引入一些你没有预料到的不可预知的错误。调试也变得更加困难,因为您不能简单地在日志中打印对象的实例,表示是正确的!您确实必须检查周围所有对象的类以捕获这些细微的错误。
在您的特定情况下,如果您打算仅在单个方法内转换字典,那么您可能会避免 subclassing 的大多数缺点dict,但是在这一点上,您为什么不简单地编写一个函数并将dicts 与它进行比较呢?这应该很好用,除非您想将dicts 传递给进行比较的库函数。