簡體   English   中英

Python 抽象 setter 和 getter

[英]Python abstract setters and getters

我想編寫摘要 class,它將強制繼承類來實現我的摘要 class 中的所有方法和屬性。

此外,我想為我的抽象屬性使用 setter 和 getter 以使我的代碼整潔且看起來不錯

但是,當前的實現:

import abc


class Component(metaclass=abc.ABCMeta):

    @property
    @abc.abstractmethod
    def status(self):
        pass

    @property
    @status.setter
    @abc.abstractmethod
    def status(self, value):
        pass

強制繼承 class 為我的抽象屬性 getter 實現 getter,但不強制創建屬性 setter(這正是我想要的)

如何在不失去應用進一步提到的方法(也就是編寫新方法並在我的抽象 class setter 中執行它們)的所有好處的情況下實現此行為?

從 abc 導入 ABCMeta,抽象方法

類基(對象):元類= ABCMeta

def __init__(self, val):
    self._foo = val

@abstractmethod
def _doStuff(self, signals):
    print ('Base does stuff')

@abstractmethod
def _get_foo(self):
    return self._foo

@abstractmethod
def _set_foo(self, val):
    self._foo = val + 'r'

foo = property(_get_foo, _set_foo)

class floor_1(Base):元類= ABCMeta

def __init__(self, val):
    self._foo = val
    super(floor_1, self).__init__(val)

def _doStuff(self, signals):
    print ('floor_1 does stuff')

def _get_foo(self):
    return self._foo

def _set_foo(self, val):
    #self._foo = val + 'r'
    super()._set_foo(val + 'r')

foo = property(_get_foo, _set_foo)

班級 floor_2(floor_1):

@property
def foo(self):
    return self._foo

@foo.setter
def foo(self, val):
    self._foo = val + 'r'
    #super()._set_foo(val + 'r')

b1 = floor_1('bar')

b1 = floor_2('bar')

打印(b1.foo)b1.foo = 'bar' 打印(b1.foo)

問題是getter和setter都不是你抽象的方法class; 它們是 property 的屬性,它是一個(不可調用的)class 屬性。 考慮這個等價的定義:

def status_getter(self):
    pass

def status_setter(self, value):
    pass

class Component(metaclass=abc.ABCMeta):
    # status = property(...)
    # status.__isabstractmethod__ = True
    status = abstractmethod(property(status_getter, status_setter))

繼承屬性與繼承方法完全不同。 您基本上是在替換該屬性,因為您的 class 本身沒有對 getter 或 setter 的引用。 盡管名稱如此, abstractmethod實際上並沒有使屬性成為方法; 它實際上無非是向應用它的任何對象添加一個屬性並返回原始值。

那么,要確保子類提供讀/寫屬性,您要做什么? 跳過裝飾器語法,將 getter 和 setter 定義為顯式抽象方法,然后根據這些私有方法顯式定義屬性。

class Component(metaclass=abc.ABCMeta):
    @abstractmethod
    def _get_status(self):
        pass

    @abstractmethod
    def _set_status(self, v):
        pass

    status = property(lambda self: self._get_status(), lambda self, v: self._set_status(self, v))

或者,您可以使用__init_subclass__ (它晚於abc ;其目的是允許 class 初始化,否則只能通過元類進行初始化)。

class Component:
    def __init_subclass(cls, **kwargs):
        super().__init_subclass__(**kwargs)

        try:
            p = cls.status
        except AttributeError:
            raise ValueError("Class does not define 'status' attribute")

        if not isinstance(p, property):
            raise ValueError("'status' is not a property")

        if p.fget is None:
            raise ValueError("'status' has no getter")

        if p.fset is None:
            raise ValueError("'status' has no setter")

在我看來,這實際上是對abc的改進。 如果子類未能定義讀/寫status屬性,則在定義class 時將引發異常,而不僅僅是在您嘗試實例化 class 時。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM