Python __getitem__ і в оператора призводять до дивної поведінки


34

Що пояснює таку поведінку:

class Foo:
    def __getitem__(self, item):
        print("?")
        return 1

f = Foo()

1 in f  # prints one ? and returns True

5 in f  # prints ? forever until you raise a Keyboard Exception

# Edit: eventually this fails with OverflowError: iter index too large

Відповіді:


45

Якщо об’єкт не має __contains__реалізації, він inповертається за замовчуванням, який в основному працює так:

def default__contains__(self, element):
    for thing in self:
        if thing == element:
            return True
    return False

І якщо об’єкт не має __iter__реалізації, він forповертається за замовчуванням, який в основному працює так:

def default__iter__(self):
    i = 0
    try:
        while True:
            yield self[i]
            i += 1
    except IndexError:
        pass

Ці параметри за замовчуванням використовуються, навіть якщо об'єкт не призначений для послідовності.

Ваші 1 in fта 5 in fтести використовують резервні резервні копії за замовчуванням для inта for, що ведуть до спостережуваної поведінки. 1 in fзнаходить 1негайно, але ваш __getitem__ніколи не повертається 5, тому 5 in fпрацює назавжди.

(Ну, насправді, у референсній реалізації Python, __iter__резервна копія за замовчуванням зберігає індекс у змінній рівня C типу Py_ssize_t, тому, якщо ви будете чекати досить довго, ця змінна виводиться назовні, і Python піднімає OverflowError . Якщо ви це бачили, ви має бути в 32-розрядному складі Python. Комп'ютери не існували досить довго, щоб хтось міг потрапити на нього на 64-бітному Python.)


Щодо OverflowError, я запускав це як на 64, так і на 32-х бітовому, і ви маєте рацію, я бачив це лише на 32-бітному.
Меттью Мойсен

Чи знаєте ви про документацію, яка пояснює це? Я хотів би ознайомитись з тим, чому було вирішено цю реалізацію.
Меттью Мойсен


4
@MatthewMoisen: Ці параметри за замовчуванням були оригінальною поведінкою forта in, що передували введенню __iter__та __contains__. Дивіться документацію на Python 1.4 тут і тут .
user2357112 підтримує Моніку
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.