Python中字段的NotImplementedError等效项

Kiv*_*Kiv 47 python abstract-class

在Python 2.x中,当您想要将方法标记为抽象时,您可以像这样定义它:

class Base:
    def foo(self):
        raise NotImplementedError("Subclasses should implement this!")
Run Code Online (Sandbox Code Playgroud)

然后,如果您忘记覆盖它,您会收到一个很好的提醒异常.是否有相同的方法将字段标记为抽象?或者在类docstring中说明它你能做什么?

起初我以为我可以将字段设置为NotImplemented,但是当我查看它的实际内容(丰富的比较)时,它似乎是侮辱性的.

Eva*_*ark 49

是的你可以.使用@property装饰器.例如,如果你有一个名为"example"的字段,那么你不能做这样的事情:

class Base(object):

    @property
    def example(self):
        raise NotImplementedError("Subclasses should implement this!")
Run Code Online (Sandbox Code Playgroud)

运行以下产生NotImplementedError就像你想要的一样.

b = Base()
print b.example
Run Code Online (Sandbox Code Playgroud)

  • 但格伦,如果财产"例子"在某个其他方面设定了怎么办?如果它立即抛出它,那么它可能永远不会有机会通过其他方式设置.请记住,字段和方法可以随时设置为类,而不仅仅是在定义类时. (4认同)
  • 这更简单,但我喜欢我的版本立即抛出,而不仅仅是属性恰好被使用. (3认同)
  • 如果我正在定义一个需要用户定义方法(或字段)的基类,我希望在基类处于活动状态时始终定义它,从__init__开始.我考虑稍后将其定义为错误,因为我可能想要从__init__访问它们.当然,您可以使用不同的规则定义类,但这似乎是最清楚的.(当然,因为我原来是一名C++程序员,所以我喜欢漂亮,严格,定义明确的接口规则.) (3认同)
  • @Glenn,两条评论:听起来像C++哲学,而Python哲学则更宽松 - 你只关心你在尝试访问一个属性时得到的东西.当你不想访问它时,它可以是任何东西,包括undefined.(当然这不是必需的,它只是编写很多Python代码的方式,我认为语言创建者/维护者的意图就是这样.) (3认同)

Gle*_*ard 33

替代答案:

@property
def NotImplementedField(self):
    raise NotImplementedError

class a(object):
    x = NotImplementedField

class b(a):
    # x = 5
    pass

b().x
a().x
Run Code Online (Sandbox Code Playgroud)

这就像Evan一样,但简洁又便宜 - 你只会获得一个NotImplementedField实例.

  • 聪明,格伦.:)我能看到的唯一缺点是,当抛出NotImplementedError时,您无法指定要显示的不同消息. (3认同)
  • 您可以将NotImplementedField定义为接收要显示的消息的函数.当没有附加消息时,你必须聪明地使用函数的单个实例来保持它 - 缓存一个没有消息的单例 - 但这就是它. (2认同)

ost*_*ach 5

一个更好的方法是使用抽象基类

import abc

class Foo(abc.ABC):

    @property
    @abc.abstractmethod
    def demo_attribute(self):
        raise NotImplementedError

    @abc.abstractmethod
    def demo_method(self):
        raise NotImplementedError

class BadBar(Foo):
    pass

class GoodBar(Foo):

    demo_attribute = 'yes'

    def demo_method(self):
        return self.demo_attribute

bad_bar = BadBar()
# TypeError: Can't instantiate abstract class BadBar \
# with abstract methods demo_attribute, demo_method

good_bar = GoodBar()
# OK
Run Code Online (Sandbox Code Playgroud)

请注意,您仍然应该拥有raise NotImplementedError而不是类似的东西pass,因为没有什么可以阻止继承类调用super().demo_method(),并且如果抽象demo_method只是pass,则这将无声地失败。

  • @Reb.Cabin 两者都是有效的。通常,当您不提供任何参数时,您会引发 `NotImplementedError`,如果您提供参数,则会引发 `raise NotImplementedError("something")`。请参阅:/sf/answers/1169645571/。 (2认同)