【问题标题】:Iterating over dictionary using __getitem__ in python [duplicate]在python中使用__getitem__迭代字典[重复]
【发布时间】:2020-08-22 17:12:12
【问题描述】:

我已经实现了一个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 = " ")

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

1 2 3 4 5 6 7 8

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

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=" ")

我希望有以下输出

a 1 b 2 c 3

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

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

我们可以像这样遍历普通字典:for key in d。这会遍历所有的键,难道不能像这样使用__getitem__()进行迭代吗?

【问题讨论】:

标签: python python-3.x dictionary iterator


【解决方案1】:

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

你的类都没有,所以 Python 会首先将你的对象传递给 iterget 一个迭代器。 iter 尝试做的第一件事是调用对象的 __iter__ 方法。

你的两个类都没有定义__iter__,所以iter接下来检查它的对象是否定义了__getitem__。你的两个类都这样做了,所以iter 返回一个iterator 类型的对象,可以想象它的__next__ 方法类似于

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

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

对于Array,这是可行的,因为它具有整数索引。但是,对于 Dictionary0 不是键,而不是引发 IndexError,而是使用 __next__ 方法得到的 KeyError 不会捕获。

(这在documentation for __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)

dict.__iter__ 返回一个dict_keyiterator 类型的值,它产生dict 的键,您可以将其与Dictionary.__getitem__ 一起使用。

【讨论】:

  • 您能否评论一下我的问题的标题是否合适?如果这与我的要求无关,我想更改它。谢谢。
  • 我认为这是相关的。问题是,如果没有任何关于可能的键可能的信息,假设键是自然数(0、1、2 等),它适用于列表但不适用于映射类型.
  • 虽然__getitem__ 的有效参数可以从dict 中检索(例如,调用keys 方法),但对于定义@ 的任意类,没有办法这样做987654356@.
【解决方案2】:

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

def __iter__(self):
    return iter(self.dictionary)

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

详情请见:https://docs.python.org/3/reference/datamodel.html?emulating-container-types#emulating-container-types

【讨论】:

  • 有道理。更改了 sn-p。
猜你喜欢
  • 2017-02-12
  • 1970-01-01
  • 2018-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-26
  • 2012-07-07
相关资源
最近更新 更多