Как включить проверку типов в абстрактный базовый класс в Python
Когда я определяю класс, мне нравится включать проверку типов (используя assert
) входных переменных. Я сейчас определяю "специализированный" класс Rule
который наследуется от абстрактного базового класса (ABC) BaseRule
, аналогично следующему:
import abc
class BaseRule(object):
__metaclass__ = abc.ABCMeta
@abc.abstractproperty
def resources(self):
pass
class Rule(BaseRule):
def __init__(self, resources):
assert all(isinstance(resource, Resource) for resource in resources) # type checking
self._resources = resources
@property
def resources(self):
return self._resources
class Resource(object):
def __init__(self, domain):
self.domain = domain
if __name__ == "__main__":
resources = [Resource("facebook.com")]
rule = Rule(resources)
assert
заявление в __init__
функция Rule
класс гарантирует, что resources
вход представляет собой список (или другой повторяемый) из Resource
объекты. Однако это также относится к другим классам, которые наследуются от BaseRule
поэтому я хотел бы включить это утверждение в abstractproperty
как-то. Как я могу пойти по этому поводу?
2 ответа
Сделайте так, чтобы ваш базовый класс имел неабстрактное свойство, которое вызывает отдельные абстрактные методы получения и установки. Свойство может выполнить необходимую проверку перед вызовом установщика. Другой код (такой как __init__
метод производного класса), который хочет запустить проверку, может сделать это, выполнив его присваивание через свойство:
class BaseRule(object):
__metaclass__ = abc.ABCMeta
@property
def resources(self): # this property isn't abstract and shouldn't be overridden
return self._get_resources()
@resources.setter
def resources(self, value):
assert all(isinstance(resource, Resources) for resource in value)
self._set_resources(value)
@abstractmethod
def _get_resources(self): # these methods should be, instead
pass
@abstractmethod
def _set_resources(self, value):
pass
class Rule(BaseRule):
def __init__(self, resources):
self.resources = resources # assign via the property to get type-checking!
def _get_resources(self):
return self._resources
def _set_resources(self, value):
self._resources = value
Вы могли бы даже рассмотреть возможность перемещения __init__
метод из Rule
в BaseRule
класс, так как ему не нужно никаких знаний о Rule
Конкретная реализация.
См. Эту документацию по аннотациям типа abc с помощью mypy-lang https://mypy.readthedocs.io/en/latest/class_basics.html