Python NotImplementedError for instance attributes
如何将实例属性标记为未在基类中实现? (与讨论将类属性标记为未实现的问题不同,但也许我没有正确理解基类......)
例如我想要类似
的东西
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | class Base(): def __init__(self): self.x = NotImplemented class GoodSub(Base): def __init__(self, x): super().__init__() self.x = x #good class BadSub(Base): def __init__(self): super().__init__() #forgot to set self.x good = GoodSub(5) bad = BadSub(-1) good.x #returns 5 bad.x #throws error because x not implemented |
或者,有没有更好的方法来强制
编辑:相关问题的链接
一个带有类装饰器和描述符的解决方案(
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | def abstract_variables(*args): class av: def __init__(self, error_message): self.error_message = error_message def __get__(self, *args, **kwargs): raise NotImplementedError(self.error_message) def f(klass): for arg in args: setattr(klass, arg, av('Descendants must set variable `{}`'.format(arg))) return klass return f @abstract_variables('x', 'y') class Base: def __init__(self): pass class Derived(Base): x = 10 b = Base() d = Derived() print(d.x) # prints 10 print(d.y) # raises NotImplementedError |
打印:
1 2 3 4 5 6 7 | 10 Traceback (most recent call last): File"main.py", line 28, in <module> print(d.y) File"main.py", line 7, in __get__ raise NotImplementedError(self.error_message) NotImplementedError: Descendants must set variable `y` |
我会考虑将
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | class Base(): def __init__(self): self.__x = None self.__x_is_set = False @property def x(self): if not self.__x_is_set: raise NotImplementedError('Descendents from Base must set x') else: return self.__x @x.setter def x(self, value): self.__x = value self.__x_is_set = True class GoodSub(Base): def __init__(self): super().__init__() self.x = 5 class BadSub(Base): def __init__(self): super().__init__() pass class AlsoBad(Base): def __init__(self): super().__init__() self.__x = 5 # sets the attribute, but not through the property |
1 2 3 4 5 6 7 8 9 10 11 12 13 | >>> g, a, b = GoodSub(), BadSub(), AlsoBad() >>> g.x 5 >>> a.x Traceback (most recent call last): File"<stdin>", line 1, in <module> File"<stdin>", line 8, in x NotImplementedError: Descendents from Base must set x >>> b.x Traceback (most recent call last): File"<stdin>", line 1, in <module> File"<stdin>", line 8, in x NotImplementedError: Descendents from Base must set x |