Почему определение метода 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:"
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__предшествует протоколу итератора, и был в прошлом только способ сделать вещи повторяемое. Таким образом, он по-прежнему поддерживается как метод итерации. По сути, протокол для итерации:
проверить
__iter__метод. Если он существует, используйте новый протокол итерации.в противном случае, попробуйте позвонить
__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