On 01/16/2017 11:32 PM, Steven D'Aprano wrote:
On Tuesday 17 January 2017 18:05, Steven D'Aprano wrote:
I wish to emulate a "final" class using Python, similar to bool:
I may have a solution: here's a singleton (so more like None than bools) where
instantiating the class returns the singleton, and subclassing the class fails:
class DoneMeta(type):
_final = None
def __new__(meta, name, bases, ns):
if meta._final is None:
meta._final = cls = super().__new__(meta, name, bases, ns)
return cls
elif meta._final in bases: # Not sure this check is needed.
raise TypeError('base class is final and cannot be subclassed')
This will make DoneMeta a one-shot, meaning you'll have to make more DoneMeta's
if you need more than one unsubclassable class.
class DoneType(metaclass=DoneMeta):
__slots__ = ()
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = inst = super().__new__(cls)
return inst
return cls._instance
def __repr__(self):
return '<DONE>'
And this has to do with single instances, which is not what you asked about.
Here's some sample code that creates a Final class; any class that subclasses
from it cannot be further subclassed:
-- 8< ------------------------------------------------------------
Final = None
class FinalMeta(type):
def __new__(metacls, cls, bases, clsdict):
print('-' * 50)
print('class: ', cls)
print('bases: ', bases)
if Final is not None:
for base in bases:
if base is not Final and issubclass(base, Final):
print('should raise')
print('-' * 50)
return type.__new__(metacls, cls, bases, clsdict)
class Final(metaclass=FinalMeta):
pass
class One(Final):
pass
class Two(One):
pass
class Three(Two):
pass
class Ten(Final):
pass
-- 8< ------------------------------------------------------------
Change the "should raise" to a raise, remove the other print()s, and away you
go.
Should work in any Python 3.
--
~Ethan~
--
https://mail.python.org/mailman/listinfo/python-list