This question is built on top of many assumptions. If one assumption is wrong, then the whole thing falls over. I\'m still relatively new to Python and have just entered the
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).
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
Final
and @final
types are now available in typing_extensions
.
I wrote an article covering almost every part of this new type: https://sobolevn.me/2018/07/real-python-contants
Some examples with classes:
from typing_extensions import final
@final
class HRBusinessUnit(AbstractBusinessUnit):
def grant_permissions(self) -> None:
self.api.do_some_hr_stuff()
class SubHRBusinessUnit(HRBusinessUnit): # mypy will raise an error
def grant_permissions(self) -> None:
self.api.do_some_it_stuff()
And with constants:
from typing_extensions import Final
DAYS_IN_A_WEEK: Final = 7
DAYS_IN_A_WEEK = 8 # mypy will raise an error
Also we have a small library to write final
classes that are also checked at runtime! https://github.com/wemake-services/final-class
from final_class import final
@final
class Example(object): # You won't be able to subclass it!
...
class Error(Example): # Raises `TypeError`
...
Features:
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.