2017-01-30 7 views
0

Когда я определяю класс, мне нравится включать проверку типов (используя assert) входных переменных. Я теперь определение «специализированный» класса Rule который наследуется от абстрактного базового класса (ABC) BaseRule, аналогичного следующий:Как включить проверку типов в абстрактном базовом классе в Python

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. Как я могу это сделать?

+0

Также посмотри на [MyPy] (http://mypy-lang.org/) для комплексного решения. – 9000

ответ

1

Сделайте свой базовый класс неабстрактным, который вызывает отдельные абстрактные методы getter и setter. Свойство может выполнить проверку, которую вы хотите, перед вызовом setter. Другой код (например, __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.

+0

Может ли быть опечатка в этом фрагменте? Потому что я получаю 'NameError: глобальное имя 'ресурс' не определен', если я использую его для замены моего кода. –

+0

Упс, да, у меня была опечатка ('для ресурсов в значении' должен был быть' для ресурса в значении'), который я теперь редактировал для исправления. Извини за это! – Blckknght