作为一个思想实验,我正在努力实现一个带有排序键的字典。 (这是为了巩固我对各种协议的理解,例如Collection
,Iterable
,Sequence
和朋友,以及如何实施它们。)
目前,我正在尝试实施Iterable
。我有一个非常基本的类,看起来像这样:
class SortedKeysDictionary:
def __init__(self, dictionary = None):
if dictionary:
self._data = dict(dictionary)
else:
self._data = {}
# Getter and setter
def get(self, key):
return self._data[key]
def set(self, key, value):
self._data[key] = value
# Iterable
def __iter__(self):
# Return a generator that sorts data
for item in sorted(self._data.__iter__()):
yield item
这似乎工作正常,因为这个测试通过了:
s = SortedKeysDictionary({"b": 1, "a": 2})
for item in s:
print(item)
但是,当我测试实例是否实际实现了协议时,就像这样,Python引发了一个错误:
s = SortedKeysDictionary()
assert issubclass(s, Iterable)
堆栈和异常是:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Program Files\Python36\lib\abc.py", line 207, in __subclasscheck__
ok = cls.__subclasshook__(subclass)
File "C:\Program Files\Python36\lib\_collections_abc.py", line 255, in __subclasshook__
return _check_methods(C, "__iter__")
File "C:\Program Files\Python36\lib\_collections_abc.py", line 73, in _check_methods
mro = C.__mro__
AttributeError: 'SortedKeysDictionary' object has no attribute '__mro__'
我对MRO和abc.collections有一些了解,但我不清楚为什么会出现这个错误(或者如何解决它)。例如,将我的类定义更改为SortedKeysDictionary(Iterable)
似乎无法解决它。对于MRO本身,我检查了{}.__mro__
返回的内容,并得到AttributeError
__mro__
不存在的内容。
我在这里缺少什么?我的课程在某种程度上是有缺陷的,还是我的测试用例无效?
作为参考,我参加了Python课程,在那里我们实现了类似的东西;我们还为issubclass(x, Sequence)
这样的事情编写了单元测试,并且在实现所需的协议之后它们似乎成功了。
无论我为哪个容器协议或子类测试issubclass
,这似乎也会提升。
答案 0 :(得分:0)
正如我在@glibdud中发现的那样,这是由于一个简单的拼写错误。 issubclass
期望(在我的用例中)两个元类作为参数,而不是类实例和元类。
要解决此问题,我只需将issubclass(s, Iterable)
更改为issubclass(SortedKeyDictionary, Iterable)
,然后按预期获得True
。
答案 1 :(得分:0)
__mro__
是特定于该类的属性,因此您无法在实例上使用issubclass
。相反,您可以使用isinstance
。
isinstance(s, Iterable) # True
我也发现它具有清晰的优点,因为它文字上要求:是实例可迭代的吗?