Python History and Design: Why issubclass() instead of rich comparisons?

565 Views Asked by At

In Python, the comparison operators -- <, <=, ==, !=, >, >= -- can be implemented to mean whatever is relevant to the implementing class. In Python 2 that was done by overriding __cmp__, and in Python 3 by overriding __lt__ and friends. What is the advantage of having an issubclass() built-in method instead of allowing for expressions such as bool < int (true), int < object (true), int <= int, or int < float (false). In particular, I'll note that classes ordered by issubclass() constitutes a partially ordered set in the mathematical sense.

The Python 3 equivalent of what I'm thinking would look like what's below. This code doesn't replace issubclass() (though looping over the MRO would accomplish that, right?). However, wouldn't this be more intuitive?

@functools.total_ordering
class Type(type):
    "Metaclass whose instances (which are classes) can use <= instead issubclass()"
    def __lt__(self, other):
        try:
            return issubclass(self, other) and self != other
        except TypeError: # other isn't a type or tuple of types
            return NotImplemented
    def __eq__(self, other):
        if isinstance(other, tuple): # For compatibility with __lt__
            for other_type in other:
                if type(self) is type(other_type):
                    return False
            return True
        else:
            return type(self) is type(other)

Actual Question: What is the advantage of having an issubclass() built-in method instead of allowing for expressions such as bool < int (true), int < object (true), int <= int, or int < float (false).

3

There are 3 best solutions below

2
On BEST ANSWER

Because it would be against the Zen of Python: http://www.python.org/dev/peps/pep-0020/

Explicit is better than implicit.

If you look at the following line of code in isolation:

issubclass(a, b)

It's perfectly obvious that a and b are variables containing classes and we are checking if a is a subclass of b. And if they happen to not contain classes, you'll know.

But looking at this

a < b

Would not tell you anything. You need to examine the surrounding code to determine they contain classes before you know that we are checking if the class in a is a subclass of b. And if say a=5 and b=6 it will still run "fine".

But Python is flexible, so if you really want this, you can implement a base type with such behaviour as you've shown.

Actually - as an aside - the prevalence of overloading operators in C++ for example is a significant drawback of the language (at least in my eyes) because when you see a + b it might as well launch a nuclear missile for all you know.... until you check types of a/b, look up the class implementation and + operator overload implementation (if any... and if not see if the parent class has any.... and if not see if the parent parent...)

3
On

One advantage in bold:

issubclass(class, classinfo)

Return true if class is a subclass (direct, indirect or virtual) of classinfo. A class is considered a subclass of itself. classinfo may be a tuple of class objects, in which case every entry in classinfo will be checked. In any other case, a TypeError exception is raised.

Another is that it's descriptive; not everyone using Python is a mathematician.

0
On

I would say the advantage is non-functional. The only technical difference is that < is infix.

But this question isn't about technical stuff. It seems to be about semantics and ease of reading.

Using < would denote order. Although class hierarchy can be interpreted as "orderable", it'll always be an approximation. A non-obvious one, for many people.

Using issubclass is clearer, still simple and doesn't lend itself to no other interpretation other than what it actually does: check if an object/classinfo is a subclass of class.

Plain, simple, unambiguous, effective. Those are the advantages. Maybe you don't/can't take advantage of them. But that's already personal taste.