2017-01-30 46 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) 

Rule類的__init__功能assert語句確保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 

你甚至可以考慮從Rule移動__init__方法進入BaseRule因爲它不需要關於Rule的具體實現的任何知識。

+0

這段代碼可能有錯字嗎?因爲我得到'NameError:全局名稱'資源'沒有定義',如果我用它來代替我的代碼。 –

+0

哎呀,是的,我確實有一個拼寫錯誤('對於資源中的資源'應該是'對於資源的價值'),我現在編輯要修復。對於那個很抱歉! – Blckknght