Python3's range objects support O(1) containment checking for integers (1) (2)
So one can do 15 in range(3, 19, 2)
and get the correct answer True
However, it doesn't support containment checking b/w two ranges
a = range(0, 10)
b = range(3, 7)
a in b # False
b in a # False, even though every element in b is also in a
a < b # TypeError: '<' not supported between instances of 'range' and 'range'
It seems that b in a
is interpreted as is any element in the range 'a' equal to the object 'b'?
However, since the range cannot contain anything but integers, range(...) in range(...)
will always return False
. IMHO, such a query should be answered as is every element in range 'b' also in range 'a'? Given that range only stores the start, stop, step and length, this query can also be answered in O(1).
The slice object doesn't help either. It doesn't implement the __contains__
method, and the __lt__
method simply compares two slices as tuples (which makes no sense)
Is there a reason behind the current implementation of these, or is it just a "it happened to be implemented this way" thing?
It looks like the implementation of __contains__
for ranges is range_contains, which just checks if the given element is in the iterable, with a special case for longs.
As you have correctly observed, e in b
returns true iff e
is an element in b
. Any other implementation, such as one that checks if e
is a subset of b
, would be ambiguous. This is especially problematic in Python, which doesn't require iterables be homogenous, and allows nested lists/tuples/sets/iterables.
Consider a world where your desired behavior was implemented. Now, suppose we have the following list:
my_list = [1, 2, (3, 4), 5]
ele1 = (3, 4)
ele2 = (2, 5)
In this case, what should ele1 in my_list
and ele2 in my_list
return? Your desired behavior makes it tedious to write code such as
if e in my_iterable:
# ah! e must exist!
my_iterable.remove(e)
A safer, better way is to keep the current behavior, and instead use a different type-sensitive operator to implement subset predicates:
x = set([1])
y = set([1,2])
x < y # True
[1] < y # raises a TypeError
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With