Comparisons and sorting of a numeric class....

Steven D'Aprano steve at pearwood.info
Tue Jan 13 06:32:31 CET 2015


On Mon, 12 Jan 2015 17:59:42 -0800, Andrew Robinson wrote:

[...]
> What I am wanting to know is WHY did Guido think it so important to do
> that ?   Why was he so focused on a strict inability to have any
> instances of a bool subclass at all -- that he made a very arbitrary
> exception to the general rule that base types in Python can be
> subclassed ?

It's not arbitrary. All the singleton (doubleton in the case of bool) 
classes cannot be subclassed. E.g. NoneType:

py> class X(type(None)):
...     pass
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Error when calling the metaclass bases
    type 'NoneType' is not an acceptable base type


Likewise for the NotImplemented and Ellipsis types.

The reason is the same: if a type promises that there is one and only one 
instance (two in the case of bool), then allowing subtypes will break 
that promise in the 99.99% of cases where the subtype is instantiated.

I suppose in principle Python could allow you to subclass singleton 
classes to your hearts content, and only raise an error if you try to 
instantiate them, but that would probably be harder and more error-prone 
to implement, and would *definitely* be harder to explain.


There may be others too:

py> from types import FunctionType
py> class F(FunctionType):
...     pass
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Error when calling the metaclass bases
    type 'function' is not an acceptable base type


My guess here is that functions are so tightly coupled to the Python 
interpreter that allowing you to subclass them, and hence break required 
invariants, could crash the interpreter. Crashing the interpreter from 
pure Python code is *absolutely not allowed*, so anything which would 
allow that is forbidden.


> There's no reason in object oriented programming principles in general
> that requires a new subclass instance to be a COMPLETELY DISTINCT
> instance from an already existing superclass instance....

True. But what is the point of such a subclass? I don't think you have 
really thought this through in detail.

Suppose we allowed bool subclasses, and we implement one which *only* 
returns True and False, without adding a third instance:

class MyBool(bool):
    def __new__(cls, arg):
        if cls.condition(arg):
            return True
        else:
            return False
    @classmethod
    def condition(cls, obj):
        # decide whether obj is true-ish or false-ish.
        pass
    def spam(self):
        return self.eggs()
    def eggs(self):
        return 23


And then you do this:

flag = MyBool(something)
flag.spam()


What do you expect to happen?


Since flag can *only* be a regular bool, True or False, it won't have 
spam or eggs methods.

You might think of writing the code using unbound methods:

MyBool.spam(flag)

(assuming that methods don't enforce the type restriction that "self" 
must be an instance of their class), but that fails when the spam method 
calls "self.eggs". So you have to write your methods like this:

    def spam(self):
        return MyBool.eggs(self)

hard-coding the class name! You can't use type(self), because that's 
regular bool, not MyBool.

This is a horrible, error-prone, confusing mess of a system. If you're 
going to write code like this, you are better off making MyBool a module 
with functions instead of a class with methods.


> nor, have I
> ever seen Guido say that Python is designed intentionally to force this
> to always be the case... so I'm not sure that's its anything more than a
> non guaranteed implementation detail that Python acts the way you say it
> does....

It is a documented restriction on bool. Whether you agree with the 
decision or not, it is not an implementation detail, it is a language 
promise.

https://docs.python.org/2/library/functions.html#bool




-- 
Steven



More information about the Python-list mailing list