Python, как сделать так, чтобы "for-iteration" останавливался на "len", используя более сложные методы - PullRequest
0 голосов
/ 30 мая 2018

У меня есть несколько классов 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 имеет длину n_values.Т.е. он не использует 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]

, но этоэто не то, что я хочу.

Кто-нибудь знает, как это исправить?

1 Ответ

0 голосов
/ 30 мая 2018

При использовании итераторов старой школы единственным способом является повышение значения IndexError:

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

. Для более чистого решения рассмотрите возможность использования более современного протокола итерации, т. Е. Возврата Итератор экземпляр из __iter__ метода, определенного в iterable .Это задокументировано здесь .

...