Python __getitem__ e l'operatore comportano comportamenti strani


34

Cosa spiega il seguente comportamento:

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

Risposte:


45

Se un oggetto non ha __contains__un'implementazione, inricade su un valore predefinito che sostanzialmente funziona in questo modo:

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

E se un oggetto non ha un __iter__ un'implementazione, forricade su un valore predefinito che sostanzialmente funziona in questo modo:

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

Queste impostazioni predefinite vengono utilizzate anche se l'oggetto non è destinato a essere una sequenza.

Your 1 in fe 5 in ftest stanno utilizzando i fallback predefiniti per ine for, portando al comportamento osservato. 1 in ftrova 1immediatamente, ma il tuo __getitem__non ritorna mai5 , quindi 5 in fcorre per sempre.

(Bene, in realtà, sull'implementazione di riferimento di Python, il __iter__fallback predefinito memorizza l'indice in una variabile di tipo C di livello Py_ssize_t, quindi se aspetti abbastanza a lungo, quella variabile si esaurisce e Python genera un OverflowError . Se lo hai visto, deve essere su una build Python a 32 bit. I computer non sono esistiti abbastanza a lungo da consentire a chiunque di raggiungerla su un Python a 64 bit.)


Per quanto riguarda OverflowError, l'ho eseguito su 64 e 32 bit, e hai ragione, l'ho visto solo su 32 bit.
Matthew Moisen,

Ti capita di conoscere la documentazione che spiega questo? Vorrei leggere il motivo per cui questa implementazione è stata decisa.
Matthew Moisen,

3
@Matthew Expressions> Operazioni di test di appartenenza , anche l' oggetto .__ contiene__ e il paragrafo sopra di esso
wjandrea

4
@MatthewMoisen: Queste impostazioni predefinite erano il comportamento originale di fore in, prima dell'introduzione di __iter__e __contains__. Consulta la documentazione di Python 1.4 qui e qui .
user2357112 supporta Monica l'
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.