我想定义一个类,以便可以将其实例强制转换为tuple
和dict
。一个例子:
class Point3:
...
p = Point(12, 34, 56)
tuple(p) # gives (12, 34, 56)
dict(p) # gives { 'x': 12, 'y': 34, 'z': 56 }
我发现,如果我将__iter__
定义为产生单个值的迭代器,则该实例可以强制转换为tuple
,如果它产生双精度值,则可以强制转换为{{1 }}:
dict
有什么方法可以使实例在Python 2.7中可同时转换为 class Point3:
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
# This way makes instance castable to tuple
def __iter__(self):
yield self.x
yield self.y
yield self.z
# This way makes instance castable to dict
def __iter__(self):
yield 'x', self.x
yield 'y', self.y
yield 'z', self.z
和tuple
?
答案 0 :(得分:6)
您可以将NamedTuple
子类化(其他类型也可以,请问医生。):
from typing import NamedTuple
class Point(NamedTuple):
x: float
y: float
z: float
def __add__(self, p):
return Point(self.x+p.x, self.y+p.y, self.z+p.z)
p = Point(1, 2, 3)
q = Point(5, 5, 5)
print(p.x, p.y, p.z)
print(p+q)
print(tuple(p))
。
$ python pointless.py
1 2 3
Point(x=6, y=7, z=8)
(1, 2, 3)
如果您使用的工具对惯用的Python有 any 注意,无论如何,命名元组应该是可以接受的。我会尝试的!
如果要使用字典,我建议使用显式的tuple(p.values())
(在子类化时)或p.coordinates
或p.xyz
作为属性(在包装时),而不要依赖某些神奇的场面。
旧版,无保修。
from collections import namedtuple
_Point = namedtuple('Point', 'x y z')
class Point(_Point):
__slots__ = ()
def __add__(self, p):
return Point(self.x+p.x, self.y+p.y, self.z+p.z)
答案 1 :(得分:3)
您无法执行您最初想做的事情(即,有两种不同的__iter__
方法),因为这没有任何意义。但是您可以使用映射协议来伪造它(见下文)。
但是,在开始之前,如果您真的想要转换为dict
,have a look at this answer以获得一些更好的选择。
我的建议是:
namedtuple
的{{1}}方法“免费”。_asdict()
时完全规避__iter__
方法。您可能会这样做;但这有点奇怪:
dict
通过上述操作,使用class Point3:
_fields = tuple("xyz")
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def __iter__(self):
for f in self._fields:
yield getattr(self, f)
def keys(self):
return self._fields
def __getitem__(self, i):
if i in self._fields:
return getattr(self, i)
raise KeyError("{!r} is not a valid field".format(i))
和dict
而非keys()
创建__getitem__()
:
__iter__
使用映射协议也可以派上用场,因为您可以“投射”(即以关键字参数的形式解压缩对象)到任何其他与关键字参数接受相同字段名称的类型,例如:>
>>> dict(Point3(1, 2, 3))
{'x': 1, 'y': 2, 'z': 3}
对于其他能够从最新版本的Python 3(3.7)中受益的人(不是OP):我强烈建议使用point= XYZer(**point3_instance)
模块:
dataclasses
像这样使用它:
from dataclasses import dataclass, asdict, astuple
@dataclass
class Point:
x: float
y: float
z: float