Final classes in Python 3.x- something Guido isn't telling me?

You can simulate the same effect from Python 3.x quite easily:

class Final(type):
    def __new__(cls, name, bases, classdict):
        for b in bases:
            if isinstance(b, Final):
                raise TypeError("type '{0}' is not an acceptable base type".format(b.__name__))
        return type.__new__(cls, name, bases, dict(classdict))

class C(metaclass=Final): pass

class D(C): pass

will give the following output:

Traceback (most recent call last):
  File "C:\Temp\final.py", line 10, in <module>
    class D(C): pass
  File "C:\Temp\final.py", line 5, in __new__
    raise TypeError("type '{0}' is not an acceptable base type".format(b.__name__))
TypeError: type 'C' is not an acceptable base type

You could do this only via the C API. Clear the Py_TPFLAGS_BASETYPE bit of the tp_flags of the type object.

Like this: http://svn.python.org/projects/python/trunk/Objects/boolobject.c (vs intobject.c where Py_TPFLAGS_BASETYPE is set).


In Python 3.6, you should block subclassing without using a metaclass like this:

class SomeBase:

    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        if cls is not SomeBase:
            raise TypeError("SomeBase does not support polymorphism.  Use composition over inheritance.")


class Derived(SomeBase):
    pass

In Python 3.8, you should also use the final decorator to induce type-checking errors:

from typing import final


@final
class SomeBase:
    ...

Type-checking is done by programs like MyPy, which are optional.