执行协议

时间:2018-03-13 19:50:30

标签: python-3.x

作为一个思想实验,我正在努力实现一个带有排序键的字典。 (这是为了巩固我对各种协议的理解,例如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 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,这似乎也会提升。

2 个答案:

答案 0 :(得分:0)

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

要解决此问题,我只需将issubclass(s, Iterable)更改为issubclass(SortedKeyDictionary, Iterable),然后按预期获得True

答案 1 :(得分:0)

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

isinstance(s, Iterable) # True

我也发现它具有清晰的优点,因为它文字上要求:是实例可迭代的吗?