简体   繁体   中英

Python __getitem__ and in operator result in strange behavior

What explains the following behavior:

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

If an object doesn't have a __contains__ implementation, in falls back on a default that basically works like this:

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

And if an object doesn't have an __iter__ implementation, for falls back on a default that basically works like this:

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

These defaults are used even if the object is not intended to be a sequence.

Your 1 in f and 5 in f tests are using the default fallbacks for in and for , leading to the observed behavior. 1 in f finds 1 immediately, but your __getitem__ never returns 5 , so 5 in f runs forever.

(Well, actually, on the reference implementation of Python, the default __iter__ fallback stores the index in a C-level variable of type Py_ssize_t , so if you wait long enough, that variable maxes out and Python raises an OverflowError . If you saw that, you must be on a 32-bit Python build. Computers haven't existed long enough for anyone to hit that on a 64-bit Python.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM