在python中使用__getitem__迭代字典

Mah*_*r I 8 python dictionary iterator python-3.x

我已经实现了一个 python 类来生成数据,如下所示:

class Array:
    def __init__(self):
        self.arr = [1,2,3,4,5,6,7,8]

    def __getitem__(self,key):
        return self.arr[key]

a = Array()
for i in a:
    print(i, end = " ")
Run Code Online (Sandbox Code Playgroud)

它按预期运行,我得到了关注

1 2 3 4 5 6 7 8
Run Code Online (Sandbox Code Playgroud)

但是,我想对字典做同样的事情。为什么我不能像这样迭代字典?

class Dictionary:
    def __init__(self):
        self.dictionary = {'a' : 1, 'b' : 2, 'c': 3}

    def __getitem__(self,key):
        return self.dictionary[key]
d = Dictionary()
for key in d:
    print(key, d[key], end=" ")
Run Code Online (Sandbox Code Playgroud)

我希望以下输出

a 1 b 2 c 3
Run Code Online (Sandbox Code Playgroud)

但是当我运行上面的代码时,出现以下错误:

Traceback (most recent call last):

  File "<ipython-input-33-4547779db7ec>", line 8, in <module>
    for key in d:

  File "<ipython-input-33-4547779db7ec>", line 6, in __getitem__
    return self.dictionary[key]

KeyError: 0
Run Code Online (Sandbox Code Playgroud)

我们可以遍历普通的字典是这样的:for key in d。这将遍历所有键,是否可以使用__getitem__()?

che*_*ner 9

一个for循环可与迭代器,对象,可以传递给next。如果一个对象有一个__next__方法,它就是一个迭代器。

无论你的班呢,所以Python会先通过你的对象iter,以获得一个迭代器。iter尝试做的第一件事是调用对象的__iter__方法。

您的两个类都没有定义__iter__,因此iter接下来检查其对象是否定义了__getitem__。你的两个类都这样做,所以iter返回一个 type 的对象iterator,其__next__方法可以被想象成是这样的

def __next__(self):
    try:
        rv = self.thing.__getitem__(self.i)
    except IndexError:
        raise StopIteration
    self.i += 1
    return rv
Run Code Online (Sandbox Code Playgroud)

(迭代器持有对定义的事物的引用__getitem__,以及i在调用__next__.之间跟踪状态的值i被假定初始化为 0。)

对于Array,这是有效的,因为它具有整数索引。对于Dictionary,虽然0不是关键和,而不是提高了IndexError,你会得到一个KeyError__next__方法并没有赶上。

(这是在文档中__getitem__提到

注意 for 循环期望为非法索引引发 IndexError 以允许正确检测序列的结尾。

)

要使您的Dictionary类可迭代,请定义__iter__

class Dictionary:
    def __init__(self):
        self.dictionary = {'a' : 1, 'b' : 2, 'c': 3}

    def __getitem__(self,key):
        return self.dictionary[key]

    def __iter__(self):
        return iter(self.dictionary)
Run Code Online (Sandbox Code Playgroud)

dict.__iter__返回一个 type 的值dict_keyiterator,它是产生dict的键的东西,您可以将其与 一起使用Dictionary.__getitem__


Sri*_*ant 8

将以下方法添加到您的Dictionary类就足以让它工作:

def __iter__(self):
    return iter(self.dictionary)
Run Code Online (Sandbox Code Playgroud)

重要说明:创建序列或映射的自定义类时,您应该实现所有相关方法。否则,您的代码(例如,等)要么效率低下x in yfor x in y要么被破坏,就像您在Dictionary类中看到的那样。

有关更多详细信息,请参阅:https : //docs.python.org/3/reference/datamodel.html?emulating-container-types#emulating-container-types