使类可以转换为元组和字典

md2*_*rpe 7 python dictionary iterable tuples python-2.7

我想定义一个类,以便它的实例可以转换为tupledict.一个例子:

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)

有没有什么办法,使浇注料,以实例 tupledict在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.coordinatesp.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)

  • 注意:从3.7开始,如果你需要一个可变类,[`dataclasses`模块](https://docs.python.org/3/library/dataclasses.html)基本上是`typing.NamedTuple的加强版本. `,但默认情况下具有可变性,以及更大的可配置性. (4认同)
  • `x:float`上的语法错误.报告的Python版本:2.7.11. (2认同)

Ric*_*ica 5

你不能做你最初想做的事情(即,有两种不同的__iter__方法),因为它没有任何意义。但是你可以使用映射协议来伪造它(见下文)。

但是,在开始之前,如果您真的想转换为 a dict,请查看此答案以获得更好的选择。


我的建议是:

  1. 执行其他答案中的建议并使用namedtuple,它为您提供_asdict()“免费”的方法。
  2. 使用映射协议实现该类(如上一个链接中所述)。如果这样做,则可以__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)