背景
最初我提出这个问题是因为我需要支持一些使用元组的混乱代码库,但没有给出其中值的任何解释。
经过一些重构,我注意到需要从其他元组中提取一些类型信息,并寻找一种无样板代码且类型安全的方法来实现它。
解决方案
您可以子类化命名元组定义并实现自定义__new__
方法来支持它,可选择在此过程中执行一些数据格式化和验证。有关更多详细信息,请参见reference。
示例
from __future__ import annotations
from collections import namedtuple
from typing import Union, Tuple
Point = namedtuple('Point', 'x y')
Color = namedtuple('Color', 'red green blue')
Pixel = namedtuple('Pixel', Point._fields + Color._fields)
class Color(Color):
def __new__(cls, *subject: Union[Pixel, Color, Tuple[float, float, float]]) -> Color:
if len(subject) == 1 and isinstance((it := subject[0]), (Pixel, Color)):
return super().__new__(cls, *cls.invalidate(it.red, it.green, it.blue))
else:
return super().__new__(cls, *cls.invalidate(*subject))
@classmethod
def invalidate(cls, r, g, b) -> Tuple[float, float, float]:
r, g, b = (float(it) for it in (r, g, b))
assert all(0 <= it <= 1.0 for it in (r, g, b)), 'Some RGB values are invalid'
return r, g, b
现在,您可以从任何支持的值类型(
Color
、
Pixel
、三个数字的三元组)实例化
Color
,而无需样板文件。
color = Color(0, 0.5, 1)
from_color = Color(color)
from_pixel = Color(Pixel(3.4, 5.6, 0, 0.5, 1))
你可以验证所有值是否相等:
>>> (0.0, 0.5, 1.0) == color == from_color == from_pixel
True
Pixel
命名元组拆分成一个Point
和一个Color
吗? - PM 2Ring