| Store | Cart

Re: Emulating Final classes in Python

From: Ethan Furman <eth...@stoneleaf.us>
Wed, 18 Jan 2017 14:02:47 -0800
On 01/18/2017 08:24 AM, Ethan Furman wrote:
> On 01/17/2017 11:05 PM, Steven D'Aprano wrote:>> I've given a metaclass that disallows subclassing:>>>> class MyClass(MyParent, metaclass=FinalMeta):>>      ...>>>>>> Ethan took that one step further by giving a class you inherit from to disallow>> subclassing:>>>> class MyClass(MyParent, Final):>>      ...>>>>>> Could we solve this problem with a decorator?>>>>>> @final>> class MyClass(MyParent):>>      ...>>>>>> Without needing to add any special magic to MyParent or MyClass, apart from the>> decorator, can we make MyClass final? That would (in principle) allow us to>> make a subclass, and *then* set the class final so that no more subclasses>> could be made.>>>>>> I thought that the decorator could simply set the class' metaclass:>>>> def final(cls):>>      if cls.__class__ is type:>>          cls.__class__ = Meta>>          return cls>>      raise TypeErrror('Possible metaclass conflict')>>>>>> but that's disallowed. Any ideas?>> You still need to have the FinalMeta type and Final class available, but to use a>  decorator you'll need to scavenge the bits from the old class to make a new class>  of the same name and return that:>> def final(cls):>      new_cls = Meta(cls.__name__, (Final, )+cls.__bases__, dict(cls.__dict__))>      return new_cls>> Not sure if more is needed to handle __slots__, but this should get us started.

One problem with the above is existing instances won't be modified to inherit from the updated class.  I am unsure if that is solvable before 3.6, but in 3.6 one can use the new __init_subclass__ to avoid a Final base class, a FinalMeta type, and just update the existing class:

def final(cls):
     def init_subclass(cls, **kwargs):
         raise Exception('Final class cannot be subclassed')
     cls.__init_subclass__ = classmethod(init_subclass)
     return cls

This can be used as a decorator at class creation time, or at any later date to lock down a class.  The downside is it's less obvious that the class is final... meaning there are no clues in the MRO.

--
~Ethan~
-- 
https://mail.python.org/mailman/listinfo/python-list

Recent Messages in this Thread
Steven DAprano Jan 17, 2017 07:05 am
Ethan Furman Jan 17, 2017 07:25 am
Steven DAprano Jan 17, 2017 07:32 am
Ethan Furman Jan 17, 2017 07:14 pm
Steve DAprano Jan 17, 2017 11:51 pm
Antoon Pardon Jan 17, 2017 09:37 am
Ethan Furman Jan 18, 2017 04:42 am
Steven DAprano Jan 18, 2017 07:05 am
Ethan Furman Jan 18, 2017 04:24 pm
Ethan Furman Jan 18, 2017 10:02 pm
Steve DAprano Jan 19, 2017 01:36 am
Steven DAprano Jan 18, 2017 02:10 am
alister Jan 18, 2017 01:43 pm
Erik Jan 17, 2017 09:54 am
Steve DAprano Jan 17, 2017 11:25 pm
Messages in this thread