Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/321.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python仅使用装饰器覆盖abstractmethod属性setter和getter_Python_Python 3.x_Inheritance_Abstract - Fatal编程技术网

Python仅使用装饰器覆盖abstractmethod属性setter和getter

Python仅使用装饰器覆盖abstractmethod属性setter和getter,python,python-3.x,inheritance,abstract,Python,Python 3.x,Inheritance,Abstract,我试图创建一个抽象类,强制实现同时实现getter和setter。我一直在关注在上所描述的内容,但我一直在关注 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 我知道有一种方法可以做到这一点,即在不使用

我试图创建一个抽象类,强制实现同时实现getter和setter。我一直在关注在上所描述的内容,但我一直在关注

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
我知道有一种方法可以做到这一点,即在不使用decorator的情况下定义属性,就像这样

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()
虽然这确实有效,但肯定有一种方法可以做到这一点,只有装饰师,不是吗


我正在运行Python3.4。

您的代码引发了一个异常,因为您在
B.foo
方法上使用了
A.foo.setter
装饰器,因此
B.foo
方法实际上没有实现具有相同签名的抽象方法
A.foo

从decorator中删除
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的定义放在两个不同的类中,这在实际应用程序中可能是不切实际的。

这里有两个不同的问题:代码中的错误(您使用了
@A.foo.setter
而不是
@foo.setter
),以及创建抽象setter。据我所知,
abc
模块不能强制您的子类实现可写属性。如果可能的话,把你的问题简化成这两个问题中的一个。哦,不能吗?这太糟糕了,听起来定义属性而不使用装饰符是一种方法。@HotCoffee:为什么要使用抽象方法?与java不同,在python中使用duck类型。我引用的python文档页面使用
@C.x.setter
,因此我遵循了这个示例。我想医生是错的。顺便说一句,虽然这消除了错误,但它不会强制子类实现setter,这是在第一种情况下使用抽象方法的要点。如果我注释掉
B
中的setter及其在
\uuuu main\uuuu
中的用法,代码运行时不会出现任何错误,但我希望它抱怨
B
没有实现抽象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()