Comparing slices in python

2019-06-25 12:16发布

问题:

Inspecting the slice class in Python with dir(), I see that it has attributes __le__ and __lt__. Indeed I saw that the following code works:

slice(1, 2) < slice(3, 4)
# True

However, I cannot see which logic is implemented for this comparison, nor its usecase. Can anyone point me to that?

I am not asking about tuple comparison. Even if slice and tuple are compared the same way, I don't think this makes my question a duplicate. What's more, I also asked for a possible usecase of slice comparison, which the suggested duplicate does not give.

回答1:

Looking at the source code for slice reveals that the comparison is implemented by first converting the two objects into (start, stop, step) tuples, and then comparing those tuples:

https://github.com/python/cpython/blob/6cca5c8459cc439cb050010ffa762a03859d3051/Objects/sliceobject.c#L598

As to the use cases, I am not sure of the authors' intent. I do note that there don't appear to be any comparison unit tests for anything other than equality:

https://github.com/python/cpython/blob/6f0eb93183519024cb360162bdd81b9faec97ba6/Lib/test/test_slice.py#L87



回答2:

Comparing tuples : (1, 2) < (3, 4) returns True because (1, 2) comes before (3, 4).

However, (1, 2) < (0, 4) returns False because (1, 2) comes after (0, 4).

NB: < and > doesn't mean smaller than or greater than, but is before and is after.

So, in other words, you're comapring which is coming before and which is coming after.

Some "odd" cases (Or, misleading cases within < and >):

(1, 2) < (3, 4, 5) returns True because the missing value of the first tuple will be equal to nil value of the operation which is zero in this case. Or you can think of it that (1, 2) come before (3, 4, 5).

And:

(0, 1) < (1, 0) will returns True because (0, 1) comes before (1, 0)

Another case:

(0, 1, 20000) < (0, 3, 1) will returns True because (0, 1, 20000) comes before (0, 3, 1).

Same logic for slice, list and even strings.

For more informations, visit this answer.



回答3:

Python data model only mentions that slice objects have three read-only attributes and one method. It does not mention any other properties of slices.

As mentioned by @NPE, CPython implementation indeed provides a comparison for slice objects, which simply treats slice as a tuple of (start, end, step). I've checked it with a small Python program which confirmed that:

vals = []
for a in range(-5, 5):
    for b in range(-5, 5):
        for c in range(-5, 5):
            vals.append((a, b, c))
for x in vals:
    for y in vals:
        assert (slice(*x) < slice(*y)) == (x < y)

However, that looks like a non-standard extension. For example, Jython also implements comparison for slices, but in a different way. Moreover, it looks like it implements comparison for all possible pairs of objects by comparing objects of the same type by their ids, which is propagated to slices.

So, order of slices in Jython is non-deterministic. For example, the following snippet prints True True on my system with Jython and True False with CPython:

print(slice(1, 2) < slice(1, 3))
print(slice(1, 3) < slice(1, 2))

Summarizing: __lt__ is implemented in CPython for some obscure reason, but it's not described anywhere in documentation and other implementations may behave not only differently, but "incorrectly" (in mathematical sense). So, one should not compare slices for inequality.



标签: python slice