【问题标题】:python how to make "for-iteration" stop at "len" using dunder methodspython如何使用dunder方法使“for-iteration”在“len”处停止
【发布时间】:2018-11-08 21:37:00
【问题描述】:

我有几个 Python 类用于调用 C 代码,使用 c-types。返回结构类似于以下示例。

import ctypes

class MyCClass(ctypes.Structure):
    _fields_ = [('n_values', ctypes.c_int),\
                ('values', ctypes.c_double * 5)]

    def __repr__(self):
        return """n_values : {0}, values : {1}""".format(self.n_values,\
                             self.values)

    def __len__(self):
        return self.n_values

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

values 数组是固定大小的,以简化对 C 的调用(此处不能使用可变大小数组)。数组的“实际”长度由n_values 变量控制。

例如,如果values 是一个由三个数字组成的数组,例如1、2 和3、values=[1, 2, 3, 0, 0] 和n_values=3。

这一切都很好。问题是当我实现__len__ 和__getitem__ 时。

我希望能够写出这样的代码

for value in my_class:
    #do something

但迭代器似乎没有“得到”values-array 只有n_values 长。 IE。它似乎没有使用MyCClass.__len__ 来停止迭代。相反,它似乎遍历了values 的整个长度。

my_class = MyCClass()

my_class.n_values = 3
sample_values = [1, 2, 3]
for i in range(3):
    my_class.values[i] = sample_values[i]

i = 0
for value in my_class:
    print(i)
    i += 1
0
1
2
3
4

我想要

i = 0
for value in my_class:
    print(i)
    i += 1
0
1
2

我知道我可以编码

for i in range(my_class):
    # do something with my_class[i]

但这不是我想要的。

有人知道如何解决这个问题吗?

【问题讨论】:

  • 在 MyCClass 中定义一个__iter__ 方法。
  • 是的,因为“旧的”基于 getitem 的迭代器协议只会继续运行,直到遇到 IndexError。只需使用__iter__ 和生成器实现迭代器协议,或者使用实现__iter__(返回自身)和__next__的自定义迭代器类

标签: python magic-methods


【解决方案1】:

对于老式迭代器类型,唯一的方法是引发IndexError:

def __getitem__(self, key):
    if key >= len(self):
        raise IndexError
    return self.values[key]

要获得更简洁的解决方案,请考虑使用更现代的迭代协议,即从 iterable 上定义的 __iter__ 方法返回 iterator 实例。这是记录在案的here。

【讨论】:

    猜你喜欢
    • 2020-10-25
    • 2022-01-06
    • 1970-01-01
    • 2020-07-24
    • 2021-11-27
    • 1970-01-01
    • 2015-02-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多