Абстрактный атрибут (не свойство)?

Какова наилучшая практика определения атрибута абстрактного экземпляра, но не как свойство?

Я хотел бы написать что-то вроде:

class AbstractFoo(metaclass=ABCMeta): @property @abstractmethod def bar(self): pass class Foo(AbstractFoo): def __init__(self): self.bar = 3 

Вместо:

 class Foo(AbstractFoo): def __init__(self): self._bar = 3 @property def bar(self): return self._bar @bar.setter def setbar(self, bar): self._bar = bar @bar.deleter def delbar(self): del self._bar 

Свойства удобны, но для простого атрибута, не требующего вычисления, они являются излишним. Это особенно важно для абстрактных классов, которые будут подклассифицированы и реализованы пользователем (я не хочу заставить кого-то использовать @property когда он просто мог написать self.foo = foo в __init__ ).

Абстрактные атрибуты в вопросе Python предлагаются только как ответ на использование @property и @abstractmethod : он не отвечает на мой вопрос.

Рецепт ActiveState для абстрактного атрибута класса через AbstractAttribute может быть правильным, но я не уверен. Он также работает только с атрибутами класса, а не с атрибутами экземпляра.

  • Как получить имя поданной формы в Flask?
  • Откройте хром-удлинитель через селен-webdriver
  • Сколько вызовов функций требуется для создания экземпляра класса?
  • Python, счетчик атомного приращения
  • Тестирование ввода пользователя со списком в python
  • лучший способ инвертировать случай строки
  • Что такое легкая библиотека python, которая может устранить теги HTML? (и только текст)
  • Копировать Python через назначение?
  • 4 Solutions collect form web for “Абстрактный атрибут (не свойство)?”

    Если вы действительно хотите обеспечить, чтобы подкласс определял данный атрибут, вы можете использовать метакласс. Лично я думаю, что это может быть излишним и не очень питоническим, но вы можете сделать что-то вроде этого:

      class AbstractFooMeta(type): def __call__(cls, *args, **kwargs): """Called when you call Foo(*args, **kwargs) """ obj = type.__call__(cls, *args, **kwargs) obj.check_bar() return obj class AbstractFoo(object): __metaclass__ = AbstractFooMeta bar = None def check_bar(self): if self.bar is None: raise NotImplementedError('Subclasses must define bar') class GoodFoo(AbstractFoo): def __init__(self): self.bar = 3 class BadFoo(AbstractFoo): def __init__(self): pass 

    В основном мета-класс переопределяет __call__ чтобы убедиться, что check_bar вызывается после init в экземпляре.

     GoodFoo()  # ok BadFoo ()  # yield NotImplementedError 

    Проблема не в том , но когда :

     from abc import ABCMeta, abstractmethod class AbstractFoo(metaclass=ABCMeta): @abstractmethod def bar(): pass class Foo(AbstractFoo): bar = object() isinstance(Foo(), AbstractFoo) #>>> True 

    Не имеет значения, что bar – это не метод! Проблема в том, что метод __subclasshook__ , метод выполнения проверки, является classmethod , поэтому classmethod только тот класс , а не экземпляр .


    Я предлагаю вам просто не навязывать это, так как это трудная проблема. Альтернатива заставляет их предопределять атрибут, но это просто оставляет фиктивные атрибуты, которые просто заглушают ошибки.

    Просто потому, что вы определяете его как abstractproperty свойство абстрактного базового класса, это не значит, что вы должны сделать свойство в подклассе.

    например, вы можете:

     In [1]: from abc import ABCMeta, abstractproperty In [2]: class X(metaclass=ABCMeta): ...: @abstractproperty ...: def required(self): ...: raise NotImplementedError ...: In [3]: class Y(X): ...: required = True ...: In [4]: Y() Out[4]: <__main__.Y at 0x10ae0d390> 

    Если вы хотите инициализировать значение в __init__ вы можете сделать это:

     In [5]: class Z(X): ...: required = None ...: def __init__(self, value): ...: self.required = value ...: In [6]: Z(value=3) Out[6]: <__main__.Z at 0x10ae15a20> 

    Некоторое время я искал об этом, но ничего не видел. Как вы знаете, знаете ли вы:

     class AbstractFoo(object): @property def bar(self): raise NotImplementedError( "Subclasses of AbstractFoo must set an instance attribute " "self._bar in it's __init__ method") class Foo(AbstractFoo): def __init__(self): self.bar = "bar" f = Foo() 

    Вы получаете AttributeError: can't set attribute который раздражает.

    Чтобы обойти это, вы можете сделать:

     class AbstractFoo(object): @property def bar(self): try: return self._bar except AttributeError: raise NotImplementedError( "Subclasses of AbstractFoo must set an instance attribute " "self._bar in it's __init__ method") class OkFoo(AbstractFoo): def __init__(self): self._bar = 3 class BadFoo(AbstractFoo): pass a = OkFoo() b = BadFoo() print a.bar print b.bar # raises a NotImplementedError 

    Это позволяет избежать AttributeError: can't set attribute но если вы просто оставите абстрактное свойство все вместе:

     class AbstractFoo(object): pass class Foo(AbstractFoo): pass f = Foo() f.bar 

    Вы получаете AttributeError: 'Foo' object has no attribute 'bar' который, возможно, почти так же хорош, как NotImplementedError. Так что действительно мое решение просто торгует одним сообщением об ошибке другого. И вы должны использовать self._bar, а не self.bar в init .

    Python - лучший язык программирования в мире.