簡體   English   中英

Python 僅使用裝飾器覆蓋抽象方法屬性設置器和獲取器

[英]Python override abstractmethod property setter and getter using decorators only

我正在嘗試創建一個抽象類,該類將強制實現同時實現 getter 和 setter。 我正在關注https://docs.python.org/3.4/library/abc.html#abc.abstractproperty 中描述的內容,但我不斷收到

Traceback (most recent call last):
  File "test.py", line 30, in <module>
    test = B('bar')
TypeError: Can't instantiate abstract class B with abstract methods foo

即使我在 B 中實現了foo getter 和 setter。

這是我的代碼:

from abc import ABC, abstractmethod

class A(ABC):
    @property
    @abstractmethod
    def foo(self):
        pass

    @foo.setter
    @abstractmethod
    def foo(self, val):
        pass

    def do_stuff(self):
        print(self.foo)

class B(A):
    def __init__(self, val):
        self._foo = val

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

    @A.foo.setter
    def foo(self, val):
        self._foo = val

if __name__ == '__main__':
    test = B('bar')
    test.do_stuff()
    test.foo = 'barr'
    test.do_stuff()

我知道有一種方法可以通過定義屬性而不使用裝飾器來做到這一點,就像這樣

from abc import ABC, abstractmethod

class A(ABC):
    @abstractmethod
    def _get_foo(self):
        pass

    @abstractmethod
    def _set_foo(self, val):
        pass

    def do_stuff(self):
        print(self.foo)

    foo = property(_get_foo, _set_foo)

class B(A):
    def __init__(self, val):
        self._foo = val

    def _get_foo(self):
        return self._foo

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

    foo = property(_get_foo, _set_foo)

if __name__ == '__main__':
    test = B('bar')
    test.do_stuff()
    test.foo = 'barr'
    test.do_stuff()

雖然這確實有效,但肯定有一種方法可以僅使用裝飾器來做到這一點,不是嗎?

我正在運行 python 3.4。

您的代碼引發異常,因為您在B.foo方法上使用A.foo.setter裝飾器,因此B.foo方法實際上並未實現具有相同簽名的抽象方法A.foo

從裝飾器中刪除A.規范,您的代碼將起作用:

@foo.setter
def foo(self, val):
    self._foo = val

通過修復,您會發現A類確實強制子類同時實現foo的 getter 和 setter(您看到的異常實際上是您沒有實現 setter 的結果)。

根據此問題,您需要查看層次結構中僅實現 getter 的附加類。 然后 setter 將留在具體類中:

from abc import ABC, abstractmethod

class A(ABC):

    @property
    @abstractmethod
    def foo(self):
        pass

    @foo.setter
    @abstractmethod
    def foo(self, val):
        pass

    def do_stuff(self):
        print(self.foo)

class B(A):

    _foo = None

    @A.foo.getter
    def foo(self):
        return self._foo

class C(B):

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

    @B.foo.setter
    def foo(self, val):
        self._foo = val

if __name__ == '__main__':
    test = C('bar')
    test.do_stuff()
    test.foo = 'barr'
    test.do_stuff()

如果您刪除 B 中的 getter 或 C 中的 setter,您將獲得所需的TypeError異常。

但是,此解決方案迫使您將 getter 和 setter 的定義放在兩個不同的類中,這在實際應用中可能不切實際。

暫無
暫無

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

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