在Python中如何使用抽象基类实现dict? [英] How would I implement a dict with Abstract Base Classes in Python?

查看:351
本文介绍了在Python中如何使用抽象基类实现dict?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图通过使用抽象基类MutableMapping在Python中实现映射,但是我在实例化上有错误。我将如何做一个这个字典的工作版本,以尽可能多的方式来模拟内置的 dict 类,以便清楚,使用抽象基础课程

 >>> D类(collections.MutableMapping):
... pass
...
>>> d = D()
追溯(最近的最后一次调用):
文件< stdin>,第1行,< module>
TypeError:无法使用抽象方法实例化抽象类D __delitem__,__getitem__,__iter__,__len__,__setitem__

一个好的答案将演示如何使这项工作,特别是没有子类化 dict 一个我非常熟悉的概念)。

解决方案


如何使用抽象基类实现dict?



一个好的答案将演示如何使这项工作,特别是
没有子类化dict。


这里是错误消息: TypeError:无法使用抽象方法__delitem__,__getitem__,__iter__,__len__,__setitem __

实例化抽象类D

事实证明,必须实施它们来使用Abst基本类(ABC), MutableMapping



实施



所以我实现了一个在大多数方面使用对象的属性引用dict进行映射的映射。 (代理与继承不同,所以我们只需要委托给实例 __ dict __ ,我们可以使用任何其他的临时映射,但是你似乎没有在Python 2中这样做是有道理的,因为MutableMapping在Python 2中没有 __ slots __ ,所以你正在创建一个在Python 3中,您可以通过设置 __ slots __ 来避免使用错误。)

  import collections 

class D(collections.MutableMapping):
'''
映射工作像一个dict和一个可变对象,即
d = D(foo ='bar')

d.foo返回'bar'
'''
从类中创建实例所需的#``__init__``方法。
def __init __(self,* args,** kwargs):
'''使用对象dict'''
self .__ dict __。update(* args,** kwargs)
#接下来的五个方法是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 __自我)
return len(self .__ dict__)
#最后两个方法不是必需的,但对于演示目的很有用:
def __str __(self):
' '返回简单的表示映射'''
return str(self .__ dict__)
def __repr __(self):
'''echoes class,id,& REPL'''
return'{},D({})'中的可重复表示格式(super(D,self).__ repr __(),
self .__ dict__)



演示



并演示用法:

 >>> d = D((e,i)for i,e in enumerate('abc'))
>>>> 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.MutableMapping

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

而一个dict总是由于注册收集导入,将成为MutableMapping的一个实例,反之并不总是如此:

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

执行此练习后,很明显,使用抽象基类只能为类的用户提供标准API的保证。在这种情况下,假设MutableMapping对象的用户将被保证为Python的标准API。



注意事项:



fromkeys 类构造方法未实现。

 >> > dict.fromkeys('abc')
{'b':无,'c':无,'a':无}
>>> D.fromkeys('abc')
追溯(最近的最后一次调用):
文件< stdin>,第1行,< module>
AttributeError:类型对象'D'没有属性'fromkeys'

内置dict方法,如 get setdefault

 >>> d ['get'] ='baz'
>>> d.get('get')
追溯(最近的最后一次调用):
文件< stdin>,第1行,< module>
TypeError:'str'对象不可调用

重新取消屏蔽相当简单: / p>

 >>> del d ['get'] 
>>> d.get('get','不在,但工作')
'不在,但工作'

但是我不会在生产中使用这个代码。






没有dict的演示,Python 3 :

 >>> class MM(MutableMapping):
... __delitem__,__getitem__,__iter__,__len__,__setitem__ =(无,)* 5
... __slots__ =()
...
>>> MM().__ dict__
追溯(最近的最后一次调用):
文件< stdin>,第1行,< module>
AttributeError:'MM'对象没有属性'__dict__'


I attempted to implement a mapping in Python by using the abstract base class, MutableMapping, but I got an error on instantiation. How would I go about making a working version of this dictionary that would emulate the builtin dict class, in as many ways as possible, to be clear, with 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__

A good answer will demonstrate how to make this work, specifically without subclassing 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.

Here's the error message: TypeError: Can't instantiate abstract class D with abstract methods __delitem__, __getitem__, __iter__, __len__, __setitem__

It turns out that one must implement them to use the Abstract Base Class (ABC), MutableMapping.

Implementation

So I implement a mapping that works like a dict in most respects that uses the object's attribute reference dict for the mapping. (Delegation is not the same as inheritance, so we'll just delegate to the instance __dict__, we could use any other ad-hoc mapping, but you don't seem to care about that part of the implementation. It makes sense to do it this way in Python 2, because MutableMapping doesn't have __slots__ in Python 2, so you're creating a __dict__ either way. In Python 3, you could avoid dicts altogether by setting __slots__.)

import collections

class D(collections.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__)

Demonstration

And to demonstrate the usage:

>>> 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]}

And for ensuring the dict API, lesson learned is that you can always check for collections.MutableMapping:

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

And while a dict is always going to be an instance of a MutableMapping due to registration on collections import, the reverse is not always true:

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

After performing this exercise, it is clear to me that using Abstract Base Classes provides only the guarantee of a standard API for users of the class. In this case, users assuming a MutableMapping object will be guaranteed the standard API for Python.

Caveats:

The fromkeys class constructor method is not implemented.

>>> 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'

One could mask the builtin dict methods like get or setdefault

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

It's fairly simple to unmask again:

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

But I wouldn't use this code in production.


Demonstration without a dict, 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中如何使用抽象基类实现dict?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆