Adding a numeric type between Real and Rational, and supporting the type's functionality for Rational numbers
Question: Python offers [a set of abstract base
classes](http://docs.python.org/3/library/numbers.html) for types of numbers.
These start with `Number`, of which `Complex` is a subclass, and so on through
`Real`, `Rational` and `Integral`. Since each is a subclass of the last, each
supports the special functionality of the classes that came before it in the
sequence. For example, you can write `(1).numerator` to get the numerator of
the Python integer `1`, created using the integer literal `1`, considered as a
rational number.

The linked page notes: _There are, of course, more possible ABCs for numbers,
and this would be a poor hierarchy if it precluded the possibility of adding
those. You can add MyFoo between Complex and Real with:_

    
    
    class MyFoo(Complex): ...
    MyFoo.register(Real)
    

This has the effect of adding a new subclass of complex numbers such that
objects of type `Real` will test as being instances of the new class - thus
adding the new class "in between" `Complex` and `Real` in some sense. This
doesn't address, however, the possibility that the new class might introduce
functionality (such as that exemplified by the `numerator` property) not
offered by its subclass.

For example, suppose that you want to add a class whose instances represent
numbers of the form `a + b√2` where `a` and `b` are rational numbers. You
would probably represent these numbers internally as a pair of `Fraction`s
(instances of `fraction.Fraction` from the Python standard library).
Evidently, this class of numbers is properly a subclass of `Real`, and we
would want to treat `Rational` as being its subclass (because every rational
number is a number of our new type in which `b == 0`). So we would do this:

    
    
    class FractionWithRoot2Part (Real): ...
    FractionWithRoot2Part.register(Rational)
    

We might want to add properties to the new class that (say) return the numbers
`a` and `b`. These properties might be called something like `RationalPart`
and `CoefficientOfRoot2`. This is awkward, however, because existing numbers
of type `Rational` will not have these properties. If we write
`(1).RationalPart` then we will get an `AttributeError`. Demonstration:

    
    
    Python 3.3.1 (v3.3.1:d9893d13c628, Apr  6 2013, 20:25:12) [MSC v.1600 32 bit (In
    tel)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    >>> from abc import *
    >>> class c1 (metaclass = ABCMeta):
    ...     def x (self): return 5
    ...
    >>> class c2: pass
    ...
    >>> c1.register(c2)
    <class '__main__.c2'>
    >>> a1 = c1()
    >>> a2 = c2()
    >>> a1.x()
    5
    >>> a2.x()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: 'c2' object has no attribute 'x'
    

Thus we have not truly introduced a new type that is "in between" the existing
two types, because the type "at the bottom" of the subclass relation does not
support the behaviours of the class "in the middle".

What is the generally accepted way to get around this? One possibility is to
provide a function (not a method of any class) which can handle any kind of
input and act intelligently; something like this:

    
    
    def RationalPart (number):
        if isinstance(number, FractionWithRoot2Part):
            try:
                return number.RationalPart
            except AttributeError:
                # number is presumably of type Rational
                return number
        else:
            raise TypeError('This is not supported you dummy!')
    

Is there a better way than this?


Answer: You can't use ABCs to modify existing classes in this way (and in fact, you
can't safely modify existing classes in this way at all). ABCs are only a
mechanism for customizing whether a class tests as a subclass of another (and
instances of it test as instances of the other), not for actually changing
subclass implementations. When the documentation talks about defining a new
class "in between", this is the sense it means; it just means in between in
terms of subclass/instance checks, not actual inheritance. This is described
[here](http://docs.python.org/3/glossary.html#term-abstract-base-class):

> ABCs introduce virtual subclasses, which are classes that don’t inherit from
> a class but are still recognized by `isinstance()` and `issubclass()`

Note what it says: the virtual subclasses _don't actually inherit_ from your
ABC, they just test as if they do. That's how ABCs are designed to work. The
way to use them is suggested
[here](http://docs.python.org/2/library/abc.html):

> An ABC can be subclassed directly, and then acts as a mix-in class.

So you can't modify the existing Rational class using ABC. The way to do what
you want is to make a new class that inherits from Rational and uses your ABC
as a mixin. Then use that class instead of the regular Rational.

In fact, you might not even really need to use ABCs here. The only advantage
of using ABCs is that it makes your new rational-like numbers look like
Rationals if anyone explicitly tests; but as long as you inherit from Rational
and from your new class that adds the behavior you want, the new classes will
_act_ like Rationals anyway.

When you say

> This is awkward, however, because existing numbers of type Rational will not
> have these properties.

you have targeted the essence of the situation. It might seem awkward, but it
would also be mighty awkward if someone could come in and, with an ABC end-
run, start modifying the behavior of your existing classes by sticking a new
superclass above them in the inheritance hierarchy. That's not how it works.
There is no safe way to add new behavior to _existing_ instances of any class;
the only safe thing is to add new behavior to your new class, and tell people
to use that new class instead of the old class.

