abc.abstractmethod + 属性

5 投票
1 回答
6718 浏览
提问于 2025-04-17 14:35

根据文档,将 @property@abc.abstractmethod 结合使用应该是可行的,所以在python3.3中,下面的代码应该可以正常工作:

import abc

class FooBase(metaclass=abc.ABCMeta):

    @property
    @abc.abstractmethod
    def greet(self):
        """ must be implemented in order to instantiate """
        pass

    @property
    def greet_comparison(self):
        """ must be implemented in order to instantiate """
        return 'hello'

class Foo(FooBase):
    def greet(self):
        return 'hello'

测试一下这个实现:

In [6]: foo = Foo()
In [7]: foo.greet
Out[7]: <bound method Foo.greet of <__main__.Foo object at 0x7f935a971f10>>

In [8]: foo.greet()
Out[8]: 'hello'

所以这显然不是一个属性,因为如果是属性的话,应该像这样工作:

In [9]: foo.greet_comparison
Out[9]: 'hello'

也许我太笨了,或者它根本就不行,有人有什么想法吗?

1 个回答

8

如果你想让 greet 成为一个属性,你还是需要在实现中使用 @property 装饰器。

class Foo(FooBase):
    @property
    def greet(self):
        return 'hello'

ABC元类的作用就是检查你在具体类中是否提供了相同的名称;它不在乎这个名称是方法、属性还是普通的变量。

因为它不在乎,所以也不会自动应用 property 装饰器。这其实是个事;因为在某些情况下,使用静态属性就足够满足需求,而使用属性可能就显得多余了。

ABC元类的目的是帮助你发现实现中的不足;它并不是用来强制规定属性的类型。

需要注意的是,在Python 3.3之前,你不能把 @property@abstractmethod 一起使用。你需要使用一个叫 @abstractproperty 装饰器。在这种情况下,如果你的属性需要的不仅仅是一个简单的获取方法,就会有些模糊;而Python 3.3对此处理得更好(详细信息可以查看 问题11610)。

撰写回答