使用typing.NamedTuple object
,对如何声明它施加附加约束的最佳方法是什么?
比方说,我有一个本科班,学生拥有一个专业,但我想强行指出,“未宣布”对于该专业来说是不可接受的价值。
from typing import NamedTuple
class Undergraduate(NamedTuple):
name: str
major: str
def check_major(self):
if self.major == "undeclared":
raise ValueError("must declare a major")
if __name__ == "__main__":
u1 = Undergraduate("Jane", "computer science") # no errors
u1.check_major() # no errors
u2 = Undergraduate("John", "undeclared") # no errors
u2.check_major() # ValueError
这很好,但是我希望每次声明一个新对象时都运行check_major()
,即:
u1 = Undergraduate("John", "undeclared") # immediate ValueError raised
是否可以仅使用NamedTuple(我知道如何使用传统类来做到这一点?
注:我读了此related question。这些解决方案提供了某种可行的解决方案,但是像OP一样,我希望能够实例化对象而无需调用其他类方法。
NamedTuple
可以防止在声明时替换__init__
和__new__
。但是,可以在创建类后替换它们。
class Radial2D(NamedTuple):
angle: float
length: float
def _verify_attributes_(self, *args):
if self.length < 0 or not 0 < self.angle < 360:
raise ValueError('Arguments out of range')
Radial2D.__init__ = Radial2D._verify_attributes_
Radial2D(90, 15.5) # Radial2D(angle=90, length=15.5)
Radial2D(12, -5) # ValueError: Arguments out of range
可以使用类装饰器简化此模式:
from typing import Type, NamedTuple
def verify(tp: Type[NamedTuple]):
verifier = tp._verify_attributes_
tp.__init__ = verifier
return tp
@verify
class Radial2D(NamedTuple):
angle: float
length: float
def _verify_attributes_(self, *args):
if self.length < 0 or not 0 < self.angle < 360:
raise ValueError('Arguments out of range')