Почему определение метода getitem на классе сделать метод в Python?



почему определение _ _ getitem__ в классе делает его итерационным?



например, если я напишу:



class b:
def __getitem__(self, k):
return k

cb = b()

for k in cb:
print k


Я получаю вывод:



0
1
2
3
4
5
6
7
8
...


Я действительно ожидал бы увидеть ошибку, возвращенную из "for k in cb:"

695   6  

6 ответов:

Если вы посмотрите на PEP234 определение итераторы, он говорит:

1. An object can be iterated over with "for" if it implements
   __iter__() or __getitem__().

2. An object can function as an iterator if it implements next().

поддержка итерации для __getitem__ можно рассматривать как" унаследованную функцию", которая позволила более плавный переход, когда PEP234 ввел итерацию в качестве основного понятия. Это относится только к классам без __iter__ чей __getitem__ принимает целые числа 0, 1, &c и поднимает IndexError как только индекс становится слишком высоким (если когда-либо), обычно классы "последовательности" кодируются до __iter__ появился (хотя ничто не мешает вам кодировать новые классы таким же образом).

лично я бы предпочел не полагаться на это в новом коде, хотя он не устарел и не уходит (отлично работает и в Python 3), так что это просто вопрос стиля и вкуса ("явное лучше, чем неявное", поэтому я бы предпочел явно поддерживать итерацию, а не полагаться на __getitem__ поддерживая его неявно для меня - но, не bigge).

__getitem__ предшествует протоколу итератора, и был в прошлом только способ сделать вещи повторяемое. Таким образом, он по-прежнему поддерживается как метод итерации. По сути, протокол для итерации:

  1. проверить __iter__ метод. Если он существует, используйте новый протокол итерации.

  2. в противном случае, попробуйте позвонить __getitem__ с последовательно большими целыми значениями, пока он не поднимет IndexError.

(2) раньше был единственным способом сделать это, но имел тот недостаток, что он предполагал больше, чем было необходимо для поддержки только итерации. Чтобы поддерживать итерацию, вам нужно было поддерживать случайный доступ, что было намного дороже для таких вещей, как файлы или сетевые потоки, где идти вперед было легко, но идти назад требовало бы хранения всего. __iter__ разрешенная итерация без произвольного доступа, но поскольку произвольный доступ обычно позволяет итерацию во всяком случае, и потому, что ломать обратную совместимость было бы плохо,__getitem__ по-прежнему поддерживается.

специальные методы, такие как __getitem__ добавить специальные поведения для объектов, включая итерации.

http://docs.python.org/reference/datamodel.html#object.getitem

" для циклов ожидается, что IndexError будет поднят для незаконных индексов, чтобы обеспечить правильное обнаружение конца последовательности."

поднять IndexError, чтобы сигнализировать конец последовательности.

ваш код в основном эквивалентен к:

i = 0
while True:
    try:
        yield object[i]
        i += 1
    except IndexError:
        break

где объект-это то, что вы перебираете в цикле for.

Это так по историческим причинам. До Python 2.2 _ _ getitem__ был единственным способом создать класс,который можно было бы повторить с помощью цикла for. В 2.2 был добавлен протокол __iter__, но для сохранения обратной совместимости __getitem__ все еще работает в циклах for.

, потому что cb[0] Это то же самое, что cb.__getitem__(0). Смотрите документация python об этом.

Comments

    Ничего не найдено.