Final classes in Python 3.x- something Guido isn't telling me?

前端 未结 4 1213
走了就别回头了
走了就别回头了 2020-12-08 13:55

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

相关标签:
4条回答
  • 2020-12-08 14:12

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

    0 讨论(0)
  • 2020-12-08 14:22

    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
    
    0 讨论(0)
  • 2020-12-08 14:25

    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:

    • No metaclass conflicts
    • No runtime overhead
    • No dependencies
    • Type hints included
    • Designed to be as simple as possible
    0 讨论(0)
  • 2020-12-08 14:30

    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.

    0 讨论(0)
提交回复
热议问题