Python 如何从另一个命名元组推断命名元组或将其子类型化?
前言 我想知道如何以python的方式概念化数据类。 具体来说,我指的是DTO(.) 我在@jeff oneill question“”中找到了一个很好的答案,其中@joe kington很好地使用了内置的Python 如何从另一个命名元组推断命名元组或将其子类型化?,python,python-2.7,dto,namedtuple,python-attrs,Python,Python 2.7,Dto,Namedtuple,Python Attrs,前言 我想知道如何以python的方式概念化数据类。 具体来说,我指的是DTO(.) 我在@jeff oneill question“”中找到了一个很好的答案,其中@joe kington很好地使用了内置的namedtuple 问题 在Python2.7文档的第8.3.4节中,介绍了如何组合多个命名元组。 我的问题是如何实现相反的效果 示例 考虑到文件中的示例: >>> p._fields # view the field names ('x', 'y')
namedtuple
问题
在Python2.7文档的第8.3.4节中,介绍了如何组合多个命名元组。
我的问题是如何实现相反的效果
示例
考虑到文件中的示例:
>>> p._fields # view the field names
('x', 'y')
>>> Color = namedtuple('Color', 'red green blue')
>>> Pixel = namedtuple('Pixel', Point._fields + Color._fields)
>>> Pixel(11, 22, 128, 255, 0)
Pixel(x=11, y=22, red=128, green=255, blue=0)
如何从“像素”实例推断“颜色”或“点”实例
最好是pythonic spirit.
Point.\u fields+Color.\u fields
只是一个元组。鉴于此:
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
Color = namedtuple('Color', 'red green blue')
Pixel = namedtuple('Pixel', Point._fields + Color._fields)
f = Point._fields + Color._fields
type(f)
只是tuple
。因此,没有办法知道它是从哪里来的
我建议您研究如何轻松处理属性对象。这将允许您进行适当的继承,并避免定义访问字段的所有好方法的开销
所以你可以
import attr
@attr.s
class Point:
x, y = attr.ib(), attr.ib()
@attr.s
class Color:
red, green, blue = attr.ib(), attr.ib(), attr.ib()
class Pixel(Point, Color):
pass
现在,
Pixel.\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。顺便说一下,如果您经常需要此操作,可以基于像素创建颜色插件
函数。甚至对于任何子名称的倍数
from collections import namedtuple
Point = namedtuple('Point', 'x y')
Color = namedtuple('Color', 'red green blue')
Pixel = namedtuple('Pixel', Point._fields + Color._fields)
pixel_ins = Pixel(x=11, y=22, red=128, green=255, blue=0)
color_ins = Color._make(getattr(pixel_ins, field) for field in Color._fields)
print color_ins
输出:颜色(红色=128,绿色=255,蓝色=0)
用于提取任意子名称的函数(无错误处理):
这里是Nikolay Prokopyev的提取子名称双倍
的替代实现,它使用字典而不是getattr
from collections import namedtuple
Point = namedtuple('Point', 'x y')
Color = namedtuple('Color', 'red green blue')
Pixel = namedtuple('Pixel', Point._fields + Color._fields)
def extract_sub_namedtuple(tup, subtype):
d = tup._asdict()
return subtype(**{k:d[k] for k in subtype._fields})
pix = Pixel(11, 22, 128, 255, 0)
point = extract_sub_namedtuple(pix, Point)
color = extract_sub_namedtuple(pix, Color)
print(point, color)
输出
Point(x=11, y=22) Color(red=128, green=255, blue=0)
这可以写成一行:
def extract_sub_namedtuple(tup, subtype):
return subtype(**{k:tup._asdict()[k] for k in subtype._fields})
但是它的效率较低,因为它必须为子类型中的每个字段调用tup.\u asdict()
。\u fields
当然,对于这些特定的namedtuple,您可以
point = Point(*pix[:2])
color = Color(*pix[2:])
但这不是很优雅,因为它硬编码父字段的位置和长度
FWIW,有代码可以将多个namedtuple组合成一个namedtuple,保留字段顺序并跳过重复的字段。另一种方法是使“Pixel”的参数与您实际需要的对齐,而不是展平其组成部分的所有参数
我认为你应该有两个参数:位置和颜色。这两个字段可以用其他元组初始化,而不必进行任何推断
例如:
#代替像素(x=11,y=22,红色=128,绿色=255,蓝色=0)
像素=像素(点(x=11,y=22),颜色(红色=128,绿色=255,蓝色=0))
#获取像素参数化的命名元组
像素颜色=像素颜色
像素点=像素位置
通过将所有参数混合在一起(例如,主对象上的x、y、红色、绿色和蓝色),您实际上没有获得任何东西,但会丢失很多易读性。如果namedtuple参数共享字段,则展平参数也会引入错误:
从集合导入namedtuple
Point=namedtuple('Point',['x','y']))
Color=namedtuple('Color','red-green-blue')
色调=命名倍数('Hue','red-green-blue')
像素=命名倍数('Pixel',Point.\u字段+颜色.\u字段+色调.\u字段)
#结果:
#回溯(最近一次呼叫最后一次):
#文件“”,第1行,在
#文件“C:\Program Files\Python38\lib\collections\\uuuuu init\uuuuu.py”,第370行,在namedtuple中
#raise VALUERROR(f'遇到重复的字段名:{name!r}')
#ValueError:遇到重复的字段名:“红色”
背景
最初我问这个问题是因为我必须支持一些意大利面代码库,它经常使用元组,但没有对元组中的值给出任何解释。
经过一些重构之后,我注意到我需要从其他元组中提取一些类型化信息,并且正在寻找一些无样板文件和类型安全的方法来实现这一点
解决方案
您可以将命名的tuple definition子类化,并实现一个自定义的\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。有关更多详细信息,请参见此
示例
from\uuuuu future\uuuuu导入注释
从集合导入namedtuple
输入importunion,Tuple
点=命名的整数('Point','xy')
Color=namedtuple('Color','red-green-blue')
像素=命名倍数('Pixel',Point.\u字段+颜色.\u字段)
#重新声明“颜色”以提供自定义创建方法
#可以从各种不同类型中推断出值
班级颜色(颜色):
def uu new uu(cls,*主题:联合[像素,颜色,元组[浮点,浮点,浮点])->颜色:
#如果只得到一个类型为“Pixel”或“Color”的参数
如果len(subject)=1且isinstance((it:=subject[0]),(像素,颜色)):
#从无效的颜色属性创建
返回super()
else:#else将其视为原始值,并在无效后对其进行旁路
返回super()
@类方法
def invalidate(cls,r,g,b)->Tuple[float,float,float]:
#将值转换为浮点值
r、 g,b=(在(r,g,b)中为它浮动(it))
#确保所有值都在有效范围内
断言所有(0>(0.0,0.5,1.0)=颜色==来自\u颜色==来自\u像素
真的
你的意思是你想把一个名为“像素”的拆分成一个点和一个颜色的吗?不完全拆分,但能够实例化“颜色”或“点”,同时只拥有一个“像素”的实例,如可接受的答案所示。好的。你可能对
point = Point(*pix[:2])
color = Color(*pix[2:])