Abstract attribute (not property)?

前端 未结 7 973
心在旅途
心在旅途 2020-11-30 22:41

What\'s the best practice to define an abstract instance attribute, but not as a property?

I would like to write something like:

class AbstractFoo(me         


        
7条回答
  •  忘掉有多难
    2020-11-30 23:17

    It's 2018, we deserve a bit better solution:

    from better_abc import ABCMeta, abstract_attribute    # see below
    
    class AbstractFoo(metaclass=ABCMeta):
    
        @abstract_attribute
        def bar(self):
            pass
    
    class Foo(AbstractFoo):
        def __init__(self):
            self.bar = 3
    
    class BadFoo(AbstractFoo):
        def __init__(self):
            pass
    

    It will behave like this:

    Foo()     # ok
    BadFoo()  # will raise: NotImplementedError: Can't instantiate abstract class BadFoo
    # with abstract attributes: bar
    

    This answer uses same approach as the accepted answer, but integrates well with built-in ABC and does not require boilerplate of check_bar() helpers.

    Here is the better_abc.py content:

    from abc import ABCMeta as NativeABCMeta
    
    class DummyAttribute:
        pass
    
    def abstract_attribute(obj=None):
        if obj is None:
            obj = DummyAttribute()
        obj.__is_abstract_attribute__ = True
        return obj
    
    
    class ABCMeta(NativeABCMeta):
    
        def __call__(cls, *args, **kwargs):
            instance = NativeABCMeta.__call__(cls, *args, **kwargs)
            abstract_attributes = {
                name
                for name in dir(instance)
                if getattr(getattr(instance, name), '__is_abstract_attribute__', False)
            }
            if abstract_attributes:
                raise NotImplementedError(
                    "Can't instantiate abstract class {} with"
                    " abstract attributes: {}".format(
                        cls.__name__,
                        ', '.join(abstract_attributes)
                    )
                )
            return instance
    

    The nice thing is that you can do:

    class AbstractFoo(metaclass=ABCMeta):
        bar = abstract_attribute()
    

    and it will work same as above.

    Also one can use:

    class ABC(ABCMeta):
        pass
    

    to define custom ABC helper. PS. I consider this code to be CC0.

    This could be improved by using AST parser to raise earlier (on class declaration) by scanning the __init__ code, but it seems to be an overkill for now (unless someone is willing to implement).

提交回复
热议问题