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

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.)


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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.