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.