__mro__实现协议时,issub类检查中缺少属性



作为一个思想实验,我正在努力实现一个带有排序键的字典。(这是为了巩固我对各种协议的理解,如CollectionIterableSequence和朋友,以及如何实现它们。

目前,我正在尝试实现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 FilesPython36libabc.py", line 207, in __subclasscheck__
ok = cls.__subclasshook__(subclass)
File "C:Program FilesPython36lib_collections_abc.py", line 255, in __subclasshook__
return _check_methods(C, "__iter__")
File "C:Program FilesPython36lib_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__返回的内容,并得到了__mro__不存在AttributeError

我在这里错过了什么?我的类在某些方面有缺陷,还是我的测试用例无效?

作为参考,我参加了一个Python课程,我们实现了类似的东西;我们还为issubclass(x, Sequence)之类的东西编写了单元测试,它们在实现所需的协议后似乎成功了。

无论我测试issubclass哪个容器协议或子类,这似乎也会引发。

正如我在@glibdud同时发现的那样,这是由于一个简单的错别字。issubclass期望(在我的用例中)两个元类作为参数,而不是类实例和元类。

为了解决这个问题,我只是将issubclass(s, Iterable)更改为issubclass(SortedKeyDictionary, Iterable),我得到了预期的True

__mro__是特定于类的属性,因此您不能在实例上使用issubclass。相反,您可以使用isinstance.

isinstance(s, Iterable) # True

我还发现这具有清晰性的优点,因为它从字面上问:实例是可迭代的吗?

最新更新