Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/296.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中字段的NotImplementedError_Python_Abstract Class - Fatal编程技术网

相当于Python中字段的NotImplementedError

相当于Python中字段的NotImplementedError,python,abstract-class,Python,Abstract Class,在Python2.x中,当您想将一个方法标记为抽象时,可以这样定义它: class Base: def foo(self): raise NotImplementedError("Subclasses should implement this!") 然后,如果你忘记覆盖它,你会得到一个很好的提醒异常。是否有一种等效的方法将字段标记为抽象字段?或者在类docstring中声明它是您唯一能做的吗 起初我以为可以将字段设置为NotImplemented,但当我查找它的实际用

在Python2.x中,当您想将一个方法标记为抽象时,可以这样定义它:

class Base:
    def foo(self):
        raise NotImplementedError("Subclasses should implement this!")
然后,如果你忘记覆盖它,你会得到一个很好的提醒异常。是否有一种等效的方法将字段标记为抽象字段?或者在类docstring中声明它是您唯一能做的吗


起初我以为可以将字段设置为NotImplemented,但当我查找它的实际用途(丰富的比较)时,它似乎是滥用的。

是的,可以。使用
@属性
装饰器。例如,如果您有一个名为“示例”的字段,那么您不能执行以下操作:

class Base(object):

    @property
    def example(self):
        raise NotImplementedError("Subclasses should implement this!")
运行以下命令会产生一个
NotImplementedError
,就像您想要的那样

b = Base()
print b.example
请注意,类类型传递到
require\u abstract\u字段
,因此,如果多个继承类使用此字段,它们不会全部验证派生最多的类的字段。你也许可以用元类自动完成,但我没有深入研究。将字段定义为“无”是可以接受的。

备选答案:

@property
def NotImplementedField(self):
    raise NotImplementedError

class a(object):
    x = NotImplementedField

class b(a):
    # x = 5
    pass

b().x
a().x

这与Evan的类似,但简洁且便宜——您只能得到一个NotImplementedField实例。

下面是我的解决方案:

def未实现方法(func):
从functools导入包装
从检查导入getargspec,formatargspec
@包装(func)
def包装器(自身、*args、**kwargs):
c=自我类名称__
m=函数名__
a=格式argspec(*getargspec(func))
raise NOTEImplementedError(“\'%s\”对象未实现方法\'%s%s\'”(c、m、a))
返回包装器
def未实现属性(func):
从functools导入包装
从检查导入getargspec,formatargspec
@包装(func)
def包装器(自身、*args、**kwargs):
c=自我类名称__
m=函数名__
raise NOTEImplementedError(“\'%s\”对象未实现属性\'%s\'”%(c,m))
返回属性(包装器、包装器、包装器)
它可以用作

类抽象库(对象):
@未实现的方法
def测试(自我):
通过
@未实现的属性
def值(自身):
通过
类实现(AbstractBase):
值=无
定义初始化(自):
self.value=42
def测试(自我):
返回真值

更好的方法是使用:


请注意,您仍然应该使用
raisenotimplementederror
而不是类似于
pass
的东西,因为没有任何东西阻止继承类调用
super().demo\u method()
,如果抽象
demo\u method
只是
pass
,则,这将以静默方式失败。

处理此问题的一个有趣模式是在父类中将属性设置为
None
,并使用确保已在子类中设置属性的函数访问该属性

以下是一个例子:


这个问题似乎对实例属性和类属性都是开放的,我将只关注第一个主题

因此,例如属性,另一种解决方法是使用以下方法定义必填字段:

屈服

pyfields.core.MandatoryFieldInitError: 
   Mandatory field 'example' has not been initialized yet 
   on instance <__main__.Base object at 0x000002C1000C0C18>.
pyfields.core.MandatoryFieldInitError:
必填字段“示例”尚未初始化
例如。
当然,它不能通过谈论子类来编辑错误消息。但在某种程度上,不谈论子类更为现实——事实上,在python中,可以在基类的实例上覆盖属性,而不仅仅是在子类中


注意:我是
pyfields
的作者。有关详细信息,请参阅。

下面是一个简单的示例,说明如何在Python 3中为子类设置所需的属性/方法

class Base:
    requires = ('foo', 'bar')

    def __init_subclass__(cls, **kwargs):
        for requirement in cls.requires:
            if not hasattr(cls, requirement):
                raise NotImplementedError(
                        f'"{cls.__name__}" must have "{requirement}".')
        super().__init_subclass__(**kwargs)

它仍然有效,即使它的初衷是为了丰富的比较。有什么问题吗?第一个问题是您可以从对象(myvar=Base.field)读取字段,接下来您知道的是,在其他部分尝试使用它并获得一个神秘的AttributeError之前,到处都没有实现。第二个问题是,在我看来,它妨碍了可读性(“那个丰富的比较在做什么?我遗漏了什么吗?”埃文的解决方案以一种熟悉的方式准确地表达了正在发生的事情。@Kiv:请不要对你的问题发表评论。请用您提出的具体观点更新您的问题。相关:这更简单,但我喜欢我的版本立即抛出的方式,不仅仅是在使用属性的情况下。但是Glenn,如果属性
示例
在其他点设置了怎么办?如果它立即抛出,那么它可能永远不会有机会通过其他方式设置。请记住,字段和方法可以在任何时候设置为类,而不仅仅是在定义类的时候。啊,这就是我所追求的。如果我定义的基类希望用户定义方法(或字段),我希望它在基类处于活动状态的任何时候都被定义,从init开始。我会考虑以后将其定义为一个错误,因为我可能想从init访问它们。当然,您可以用不同的规则定义类,但这似乎是最清晰的。(当然,我最初是一个C++程序员,我喜欢好的、严格的、定义良好的接口规则。)格伦,两个评论:听起来像C++哲学,而Python哲学则更宽松——你只关心当你尝试访问一个属性时你得到了什么。当您不尝试访问它时,它可以是任何内容,包括未定义的内容。(当然,这不是必需的,这只是许多Python代码的编写方式,我认为语言创建者/维护者的意图就是这样。)聪明,Glenn.:)我能看到的唯一缺点是,当抛出NotImplementedError时,您不能指定要显示的不同消息。您可以将NotImplementedField定义为一个函数,用于显示消息。你得聪明一点,用单曲来保持它
class GenericAPIView(views.APIView):

    [...]

    serializer_class = None

    [...]

    def get_serializer_class(self):
        assert self.serializer_class is not None, (
            "'%s' should either include a `serializer_class` attribute, "
            "or override the `get_serializer_class()` method."
            % self.__class__.__name__
        )

        return self.serializer_class
from pyfields import field

class Base(object):
    example = field(doc="This should contain an example.")

b = Base()
b.example
pyfields.core.MandatoryFieldInitError: 
   Mandatory field 'example' has not been initialized yet 
   on instance <__main__.Base object at 0x000002C1000C0C18>.
class Base:
    requires = ('foo', 'bar')

    def __init_subclass__(cls, **kwargs):
        for requirement in cls.requires:
            if not hasattr(cls, requirement):
                raise NotImplementedError(
                        f'"{cls.__name__}" must have "{requirement}".')
        super().__init_subclass__(**kwargs)