Python __getitem__ dan pada operator menghasilkan perilaku aneh

34

Apa yang menjelaskan perilaku berikut:

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
Matthew Moisen
sumber

Jawaban:

45

Jika suatu objek tidak memiliki __contains__implementasi, inkembali ke default yang pada dasarnya bekerja seperti ini:

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

Dan jika suatu objek tidak memiliki __iter__implementasi, forkembali ke default yang pada dasarnya bekerja seperti ini:

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

Default ini digunakan bahkan jika objek tidak dimaksudkan sebagai urutan.

Tes Anda 1 in fdan 5 in fmenggunakan fallback default untuk indan for, yang mengarah ke perilaku yang diamati. segera 1 in fditemukan 1, tetapi Anda __getitem__tidak pernah kembali 5, jadi 5 in fjalankan selamanya.

(Ya, sebenarnya, pada implementasi referensi Python, __iter__fallback default menyimpan indeks dalam tipe variabel level-C Py_ssize_t, jadi jika Anda menunggu cukup lama, variabel itu akan keluar dan Python memunculkan OverflowError . Jika Anda melihatnya, Anda harus menggunakan Python build 32-bit. Komputer belum ada cukup lama bagi siapa pun untuk menekan itu pada Python 64-bit.)

user2357112 mendukung Monica
sumber
Mengenai OverflowError, saya menjalankan ini pada 64 dan 32 bit, dan Anda benar saya hanya melihatnya di 32 bit.
Matius Moisen
Apakah Anda mengetahui dokumentasi yang menjelaskan hal ini? Saya ingin membaca mengapa implementasi ini diputuskan.
Matthew Moisen
3
@Matthew Expressions> Operasi tes keanggotaan , juga objek .__ berisi__ dan paragraf di atasnya
wjandrea
4
@ MatthewMoisen: Default ini adalah perilaku asli dari fordan in, sebelum pengenalan __iter__dan __contains__. Lihat dokumentasi Python 1.4 di sini dan di sini .
user2357112 mendukung Monica