Emulating Final classes in Python

Steve D'Aprano steve+python at pearwood.info
Tue Jan 17 18:51:03 EST 2017

On Wed, 18 Jan 2017 06:14 am, Ethan Furman wrote:

> 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.

For my purposes, that's enough -- I only have one object that I actually
need, something which is like None or Ellipsis or NotImplemented, just a
unique and featureless point-particle with no state or behaviour (apart
from a neat repr).

Yes yes, it's that damn singleton design (anti-)pattern again :-)

It's a bit ... something ... that to make a single stateless, behaviourless
instance I need a class and a metaclass, but that's Python for you.

As an alternative, I may use a single Enum, and delete the class object
after I've extracted the enumeration:

from enum import Enum

class DoneType(Enum):
    DONE = 'Done'

DONE = DoneType(DONE)
del DoneType

Although enumerations have more behaviour than I need, maybe this is close
enough that I don't care.

>> 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.

Very observant of you :-)

> Here's some sample code that creates a Final class; any class that
> subclasses from it cannot be further subclassed:


“Cheer up,” they said, “things could be worse.” So I cheered up, and sure
enough, things got worse.

More information about the Python-list mailing list