pythoncomputer-sciencelanguage-designlanguage-history

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


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


Solution

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