python - 我将如何在 Python 中实现带有抽象基类的字典?

标签 python dictionary abc

<分区>

我尝试使用抽象基类 MutableMapping 在 Python 中实现映射,但在实例化时遇到错误。我将如何着手制作这本字典的工作版本,以尽可能多的方式模拟内置的 dict 类,使用 Abstract Base Classes 来明确?

>>> class D(collections.MutableMapping):
...     pass
... 
>>> d = D()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class D with abstract methods __delitem__, __getitem__, __iter__, __len__, __setitem__

一个好的答案将演示如何使它工作,特别是在不子类化 dict ( a concept that I am quite familiar with ) 的情况下。

最佳答案

How would I implement a dict with Abstract Base Classes?

A good answer will demonstrate how to make this work, specifically without subclassing dict.

错误信息如下:TypeError: Can't instantiate abstract class D with abstract methods __delitem__, __getitem__, __iter__, __len__, __setitem__

事实证明,必须实现它们才能使用抽象基类 (ABC),MutableMapping

实现

所以我实现了一个在大多数方面都像字典一样工作的映射,它使用对象的属性引用字典进行映射。 (委托(delegate)与继承不同,所以我们只委托(delegate)给实例__dict__,我们可以使用任何其他的临时映射,但你似乎并不关心那部分实现。在 Python 2 中这样做是有意义的,因为 MutableMapping 在 Python 2 中没有 __slots__,所以无论哪种方式,你都在创建一个 __dict__。在Python 3,你可以通过设置 __slots__ 来完全避免字典。)

from collections.abc import MutableMapping

class D(MutableMapping):
    '''
    Mapping that works like both a dict and a mutable object, i.e.
    d = D(foo='bar')
    and 
    d.foo returns 'bar'
    '''
    # ``__init__`` method required to create instance from class.
    def __init__(self, *args, **kwargs):
        '''Use the object dict'''
        self.__dict__.update(*args, **kwargs)
    # The next five methods are requirements of the ABC.
    def __setitem__(self, key, value):
        self.__dict__[key] = value
    def __getitem__(self, key):
        return self.__dict__[key]
    def __delitem__(self, key):
        del self.__dict__[key]
    def __iter__(self):
        return iter(self.__dict__)
    def __len__(self):
        return len(self.__dict__)
    # The final two methods aren't required, but nice for demo purposes:
    def __str__(self):
        '''returns simple dict representation of the mapping'''
        return str(self.__dict__)
    def __repr__(self):
        '''echoes class, id, & reproducible representation in the REPL'''
        return '{}, D({})'.format(super(D, self).__repr__(), 
                                  self.__dict__)

演示

并演示用法:

>>> d = D((e, i) for i, e in enumerate('abc'))
>>> d
<__main__.D object at 0x7f75eb242e50>, D({'b': 1, 'c': 2, 'a': 0})
>>> d.a
0
>>> d.get('b')
1
>>> d.setdefault('d', []).append(3)
>>> d.foo = 'bar'
>>> print(d)
{'b': 1, 'c': 2, 'a': 0, 'foo': 'bar', 'd': [3]}

为了确保 dict API,经验教训是您始终可以检查 collections.abc.MutableMapping:

>>> isinstance(d, MutableMapping)
True
>>> isinstance(dict(), MutableMapping)
True

虽然由于在集合导入时注册,字典总是成为 MutableMapping 的实例,但反之并不总是正确的:

>>> isinstance(d, dict)
False
>>> isinstance(d, (dict, MutableMapping))
True

完成这个练习后,我很清楚使用抽象基类只能为类的用户提供标准 API 的保证。在这种情况下,假定 MutableMapping 对象的用户将保证使用 Python 的标准 API。

注意事项:

fromkeys 类构造器方法未实现。

>>> dict.fromkeys('abc')
{'b': None, 'c': None, 'a': None}
>>> D.fromkeys('abc')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'D' has no attribute 'fromkeys'

可以屏蔽内置的 dict 方法,如 getsetdefault

>>> d['get'] = 'baz'
>>> d.get('get')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object is not callable

再次揭开面具相当简单:

>>> del d['get']
>>> d.get('get', 'Not there, but working')
'Not there, but working'

但我不会在生产中使用此代码。


没有字典的演示,Python 3:

>>> class MM(MutableMapping):
...   __delitem__, __getitem__, __iter__, __len__, __setitem__ = (None,) *5
...   __slots__ = ()
...
>>> MM().__dict__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'MM' object has no attribute '__dict__'

关于python - 我将如何在 Python 中实现带有抽象基类的字典?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21361106/

相关文章:

python - 如何合并具有相同键的 python 字典,如果数据可用,则特定值将始终被覆盖

python - 使用带有 `abc` 库的抽象类时获取 python 类名

python - Python 中的抽象方法继承

python - 抽象类和字典的 mypy 问题

python - 如何将字符串中的文字转义序列转换为相应的字节?

python - 为什么我收到额外的标签文本而不是我放入的实际标签?

javascript - 您可以使用 Array.map 来根据条件摆脱它所作用的元素吗?

python - 如果字典列表不包含特定值,请检查 python

python - 面向对象编程Python : Where to instantiate Cassandra and elasticsearch cluster?

python - 根据条件获取其他模型字段的总和