在声明 typing.NamedTuple 对象时提供额外的约束
provide additional constraints when declaring typing.NamedTuple object
使用 typing.NamedTuple object
,对它的声明方式实施额外约束的最佳方法是什么?
假设我有一个本科 class 学生有一个专业,但我想强制执行 'undeclared' 对于专业来说是一个不可接受的值。
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 是否可行(我知道如何使用传统的 classes 实现)?
注意:我读了这个related question。这些解决方案提供了一些可行的解决方案,但与 OP 一样,我希望能够实例化对象而无需调用额外的 class 方法。
NamedTuple
保护 __init__
和 __new__
在声明时不被替换。但是,它们可以在 class 创建后被替换。
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_
print(Radial2D(90, 15.5)) # Radial2D(angle=90, length=15.5)
print(Radial2D(12, -5)) # ValueError: Arguments out of range
可以使用 class 装饰器简化此模式:
from typing import Type, NamedTuple
def verify(tp: Type[NamedTuple]):
verifier = tp._verify_attributes_
tp.__init__ = verifier
return tp
@verify
class Undergraduate(NamedTuple):
name: str
major: str
def _verify_attributes_(self, *args):
if self.major == "undeclared":
raise ValueError("must declare a major")
print(Undergraduate("Jane", "computer science")) # Undergraduate(name='Jane', major='computer science')
print(Undergraduate("John", "undeclared")) # ValueError: must declare a major
使用 typing.NamedTuple object
,对它的声明方式实施额外约束的最佳方法是什么?
假设我有一个本科 class 学生有一个专业,但我想强制执行 'undeclared' 对于专业来说是一个不可接受的值。
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 是否可行(我知道如何使用传统的 classes 实现)?
注意:我读了这个related question。这些解决方案提供了一些可行的解决方案,但与 OP 一样,我希望能够实例化对象而无需调用额外的 class 方法。
NamedTuple
保护 __init__
和 __new__
在声明时不被替换。但是,它们可以在 class 创建后被替换。
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_
print(Radial2D(90, 15.5)) # Radial2D(angle=90, length=15.5)
print(Radial2D(12, -5)) # ValueError: Arguments out of range
可以使用 class 装饰器简化此模式:
from typing import Type, NamedTuple
def verify(tp: Type[NamedTuple]):
verifier = tp._verify_attributes_
tp.__init__ = verifier
return tp
@verify
class Undergraduate(NamedTuple):
name: str
major: str
def _verify_attributes_(self, *args):
if self.major == "undeclared":
raise ValueError("must declare a major")
print(Undergraduate("Jane", "computer science")) # Undergraduate(name='Jane', major='computer science')
print(Undergraduate("John", "undeclared")) # ValueError: must declare a major