在声明类型时提供附加约束。NamedTuple对象

问题描述 投票:0回答:1

使用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一样,我希望能够实例化对象而无需调用其他类方法。

python-3.x namedtuple
1个回答
0
投票

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')
© www.soinside.com 2019 - 2024. All rights reserved.