Abstract attribute (not property)?

前端 未结 7 971
心在旅途
心在旅途 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:10

    As Anentropic said, you don't have to implement an abstractproperty as another property.

    However, one thing all answers seem to neglect is Python's member slots (the __slots__ class attribute). Users of your ABCs required to implement abstract properties could simply define them within __slots__ if all that's needed is a data attribute.

    So with something like,

    class AbstractFoo(abc.ABC):
        __slots__ = ()
    
        bar = abc.abstractproperty()
    

    Users can define sub-classes simply like,

    class Foo(AbstractFoo):
        __slots__ = 'bar',  # the only requirement
    
        # define Foo as desired
    
        def __init__(self):
            self.bar = ...
    

    Here, Foo.bar behaves like a regular instance attribute, which it is, just implemented differently. This is simple, efficient, and avoids the @property boilerplate that you described.

    This works whether or not ABCs define __slots__ at their class' bodies. However, going with __slots__ all the way not only saves memory and provides faster attribute accesses but also gives a meaningful descriptor instead of having intermediates (e.g. bar = None or similar) in sub-classes.1

    A few answers suggest doing the "abstract" attribute check after instantiation (i.e. at the meta-class __call__() method) but I find that not only wasteful but also potentially inefficient as the initialization step could be a time-consuming one.

    In short, what's required for sub-classes of ABCs is to override the relevant descriptor (be it a property or a method), it doesn't matter how, and documenting to your users that it's possible to use __slots__ as implementation for abstract properties seems to me as the more adequate approach.


    1 In any case, at the very least, ABCs should always define an empty __slots__ class attribute because otherwise sub-classes are forced to have __dict__ (dynamic attribute access) and __weakref__ (weak reference support) when instantiated. See the abc or collections.abc modules for examples of this being the case within the standard library.

提交回复
热议问题