为什么Python不支持记录类型?(即可变名称对)

为什么Python不支持记录类型?(即可变名称对),python,collections,namedtuple,Python,Collections,Namedtuple,为什么Python本机不支持记录类型?这是一个拥有namedtuple的可变版本的问题 我可以使用namedtuple.\u替换。但是我需要将这些记录保存在一个集合中,因为命名为tuple.\u replace创建了另一个实例,所以我还需要修改集合,该集合很快就会变得混乱 背景: 我有一个设备,我需要通过TCP/IP轮询它来获取它的属性。i、 它的表示是一个可变对象 编辑: 我有一套需要投票的设备 编辑: 我需要使用PyQt遍历对象,显示其属性。我知道我可以添加一些特殊的方法,比如\uu get

为什么Python本机不支持记录类型?这是一个拥有namedtuple的可变版本的问题

我可以使用
namedtuple.\u替换
。但是我需要将这些记录保存在一个集合中,因为
命名为tuple.\u replace
创建了另一个实例,所以我还需要修改集合,该集合很快就会变得混乱

背景: 我有一个设备,我需要通过TCP/IP轮询它来获取它的属性。i、 它的表示是一个可变对象

编辑: 我有一套需要投票的设备

编辑: 我需要使用PyQt遍历对象,显示其属性。我知道我可以添加一些特殊的方法,比如
\uu getitem\uuuuuuuuu
\uuuu iter\uuuuuuuuu
,但我想知道是否有更简单的方法

编辑:
我更喜欢属性是固定的(就像在我的设备中一样),但属性是可变的类型。

有什么原因不能使用常规词典吗?在您的特定情况下,属性似乎没有特定的顺序

或者,您也可以使用类实例(具有良好的属性访问语法)。如果希望避免为每个实例创建
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

我还发现了一个,它被描述为可变的命名元组。它们是使用类实现的

更新:

既然您说顺序对您的场景很重要(并且您希望遍历所有属性),那么
OrderedDict
似乎是一种方法。从Python 2.7开始,这是标准
集合
模块的一部分;对于Python<2.7,互联网上还存在其他浮动版本

要添加属性样式访问,可以按如下方式将其子类化:

from collections import OrderedDict

class MutableNamedTuple(OrderedDict):
    def __init__(self, *args, **kwargs):
        super(MutableNamedTuple, self).__init__(*args, **kwargs)
        self._initialized = True

    def __getattr__(self, name):
        try:
            return self[name]
        except KeyError:
            raise AttributeError(name)

    def __setattr__(self, name, value):
        if hasattr(self, '_initialized'):
            super(MutableNamedTuple, self).__setitem__(name, value)
        else:
            super(MutableNamedTuple, self).__setattr__(name, value)
然后你可以做:

>>> t = MutableNamedTuple()
>>> t.foo = u'Crazy camels!'
>>> t.bar = u'Yay, attribute access'
>>> t.foo
u'Crazy camels!'
>>> t.values()
[u'Crazy camels!', u'Yay, attribute access']

这可以使用空类及其实例来完成,如下所示:

>>> class a(): pass
... 
>>> ainstance = a()
>>> ainstance.b = 'We want Moshiach Now'
>>> ainstance.b
'We want Moshiach Now'
>>> 

Python有一个类似于namedtuple的库,但它是可变的,称为recordtype

套餐主页:

简单的例子:

from recordtype import recordtype

Person = recordtype('Person', 'first_name last_name phone_number')
person1 = Person('Trent', 'Steele', '637-3049')
person1.last_name = 'Terrence';

print person1
# Person(first_name=Trent, last_name=Terrence, phone_number=637-3049)
Basis = recordtype('Basis', [('x', 1), ('y', 0)])
简单的默认值示例:

from recordtype import recordtype

Person = recordtype('Person', 'first_name last_name phone_number')
person1 = Person('Trent', 'Steele', '637-3049')
person1.last_name = 'Terrence';

print person1
# Person(first_name=Trent, last_name=Terrence, phone_number=637-3049)
Basis = recordtype('Basis', [('x', 1), ('y', 0)])
依次遍历
person1
的字段:

map(person1.__getattribute__, Person._fields)

您可以这样做
dict
子类,它是它自己的
\uuuuu dict\uuuu
。基本概念与ActiveState配方相同,但实现更简单。由于实例的属性及其值都是可变的,因此结果比您需要的更可变。虽然属性没有排序,但您可以遍历当前属性和/或它们的值

class Record(dict):
    def __init__(self, *args, **kwargs):
        super(Record, self).__init__(*args, **kwargs)
        self.__dict__ = self

这个“frozenclass”装饰器基于多年来收集的几个有用的技巧,几乎完成了所需的一切:

由于这段代码有超过70%的文档和测试,我在这里不再赘述。

这个答案重复。 对于
集合,有一种可变的替代方法。namedtuple
-

它与namedtuple具有相同的API和内存占用(实际上它也更快)。It支持作业。例如:

from recordclass import recordclass

Point = recordclass('Point', 'x y')

>>> p = Point(1, 2)
>>> p
Point(x=1, y=2)
>>> print(p.x, p.y)
1 2
>>> p.x += 2; p.y += 3; print(p)
Point(x=3, y=5)

还有更完整的(它还包括性能比较)。

这里是我制作的一个完整的可变名称的tuple,它的行为类似于一个列表,并且与它完全兼容

class AbstractNamedArray():
    """a mutable collections.namedtuple"""
    def __new__(cls, *args, **kwargs):
        inst = object.__new__(cls)  # to rename the class
        inst._list = len(cls._fields)*[None]
        inst._mapping = {}
        for i, field in enumerate(cls._fields):
            inst._mapping[field] = i
        return inst

    def __init__(self, *args, **kwargs):
        if len(kwargs) == 0 and len(args) != 0:
            assert len(args) == len(self._fields), 'bad number of arguments'
            self._list = list(args)
        elif len(args) == 0 and len(kwargs) != 0:
            for field, value in kwargs.items():
                assert field in self._fields, 'field {} doesn\'t exist'
                self._list[self._mapping[field]] = value
        else:
            raise ValueError("you can't mix args and kwargs")

    def __getattr__(self, x):
        return object.__getattribute__(self, '_list')[object.__getattribute__(self, '_mapping')[x]]

    def __setattr__(self, x, y):
        if x in self._fields:
            self._list[self._mapping[x]] = y
        else:
            object.__setattr__(self, x, y)

    def __repr__(self):
        fields = []
        for field, value in zip(self._fields, map(self.__getattr__, self._fields)):
            fields.append('{}={}'.format(field, repr(value)))
        return '{}({})'.format(self._name, ', '.join(fields))

    def __iter__(self):
        yield from self._list

    def __list__(self):
        return self._list[:]

    def __len__(self):
        return len(self._fields)

    def __getitem__(self, x):
        return self._list[x]

    def __setitem__(self, x, y):
        self._list[x] = y

    def __contains__(self, x):
        return x in self._list

    def reverse(self):
        self._list.reverse()

    def copy(self):
        return self._list.copy()


def namedarray(name, fields):
    """used to construct a named array (fixed-length list with named fields)"""
    return type(name, (AbstractNamedarray,), {'_name': name, '_fields': fields})
在密切相关的问题中,13项测试用于比较6个可变备选方案与
namedtuple

从2016年1月11日起,最新的1.7版本将使用Python 2.7和Python 3.5进行所有这些测试这是一个纯python实现。

根据这些测试,第二个最好的候选者是C扩展。当然,是否首选C扩展取决于您的需求


有关更多详细信息,特别是测试,请参见

这个问题很老了,但为了完整起见,Python 3.7有很多记录

>>> from dataclasses import dataclass
>>>
>>> @dataclass
... class MyRecord:
...     name: str
...     age: int = -1
...
>>> rec = MyRecord('me')
>>> rec.age = 127
>>> print(rec)
MyRecord(name='me', age=127)
ATTR第三方库为Python 2和Python 3提供了更多功能。如果需求更多地围绕您不能在本地保留的内容,而不是只使用stdlib,那么供应商依赖关系也没有什么错。dephell有一个很好的助手来做这件事。

As,因为Python≥在3.3中,Python确实有一个namedtuple的可变版本:

这些东西和新的非常相似

下面是一些用法示例:

位置构造函数参数 导入类型 >>> >>>类位置(types.SimpleNamespace): ... def uuu init uuuu(self,lat=0,long=0): ... 超级() ... >>>loc_1=位置(49.4,8.7)
漂亮的报告 易变的 平等的价值语义 可以在运行时添加属性
您甚至可以将
dict
类分为子类,并分别使(IIRC)
\uuuuuu getattr\uuuuuuu
\uuuuuu setattr\uuuuuuuuu
同义于
\uuuuuu getitem\uuuuuuuuuuuuuu
。@Chris我认为我最喜欢那种方法(而且您的记忆是正确的,这些方法)+1用于指定为每个类创建一次插槽,同时为每个实例创建dict。我已编辑了我的问题,以包括订购的需要。而且,我知道这张唱片的配方;然而,我想知道为什么Python社区认为不需要标准记录类型。如果需要排序,请尝试OrderedDict。我相信它也在收藏模块中。谢谢。我更喜欢属性是固定的(就像在我的设备中一样),但属性是可变的类型。我想我可能必须选择Cameron指定的记录类型。创建一个类或使用dict。两者都是可变的,都允许您按名称访问其中的值。@dappawit,这是正确的。但是使用dict,我将无法方便地将属性作为字段。我避免使用类,因为我需要遍历对象,将其视为属性集合。我将编辑我的帖子以指定此要求。我知道我总是可以添加特殊的方法,将其视为一个集合。但我想知道是否
>>> loc_1
Location(lat=49.4, long=8.7)
>>> loc_2 = Location()
>>> loc_2
Location(lat=0, long=0)
>>> loc_2.lat = 49.4
>>> loc_2
Location(lat=49.4, long=0)
>>> loc_2 == loc_1
False
>>> loc_2.long = 8.7
>>> loc_2 == loc_1
True
>>> loc_2.city = 'Heidelberg'
>>> loc_2