md2*_*rpe 7 python dictionary iterable tuples python-2.7
我想定义一个类,以便它的实例可以转换为tuple和dict.一个例子:
class Point3:
...
p = Point(12, 34, 56)
tuple(p) # gives (12, 34, 56)
dict(p) # gives { 'x': 12, 'y': 34, 'z': 56 }
Run Code Online (Sandbox Code Playgroud)
我发现如果我定义__iter__为一个产生单个值的迭代器,那么实例可以被转换为tuple,如果它产生双值,那么它可以被转换为dict:
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
Run Code Online (Sandbox Code Playgroud)
有没有什么办法,使浇注料,以实例都 tuple和dict在Python 2.7?
小智 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))
Run Code Online (Sandbox Code Playgroud)
.
$ python pointless.py
1 2 3
Point(x=6, y=7, z=8)
(1, 2, 3)
Run Code Online (Sandbox Code Playgroud)
如果您使用的工具对于惯用Python 有任何考虑,那么无论如何,命名元组应该是可接受的.我会尝试一下!
如果你要使用字典,我建议使用显式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)
Run Code Online (Sandbox Code Playgroud)
你不能做你最初想做的事情(即,有两种不同的__iter__方法),因为它没有任何意义。但是你可以使用映射协议来伪造它(见下文)。
但是,在开始之前,如果您真的想转换为 a dict,请查看此答案以获得更好的选择。
我的建议是:
namedtuple,它为您提供_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))
Run Code Online (Sandbox Code Playgroud)
有了上面的内容,dict是使用keys()and__getitem__()而不是创建的__iter__:
>>> dict(Point3(1, 2, 3))
{'x': 1, 'y': 2, 'z': 3}
Run Code Online (Sandbox Code Playgroud)
使用映射协议也可以派上用场,因为您可以“强制转换”(即,以关键字参数的形式将对象解包)为接受与关键字参数相同的字段名称的任何其他类型,例如:
point= XYZer(**point3_instance)
Run Code Online (Sandbox Code Playgroud)
对于能够从最新版本的 Python 3 (3.7) 中受益的其他人(不是 OP):我强烈建议使用该dataclasses模块:
from dataclasses import dataclass, asdict, astuple
@dataclass
class Point:
x: float
y: float
z: float
Run Code Online (Sandbox Code Playgroud)
像这样使用它:
>>> p = Point(1,2,3)
>>> asdict(p)
{'x': 1, 'y': 2, 'z': 3}
>>> astuple(p)
(1, 2, 3)
Run Code Online (Sandbox Code Playgroud)