为什么Python不支持记录类型?(即可变的namedtuple)

Sal*_*lil 48 python collections namedtuple

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

我可以用namedtuple._replace.但我需要在集合中包含这些记录,并且由于namedtuple._replace创建了另一个实例,我还需要修改快速变得混乱的集合.

背景:我有一个设备,我需要通过TCP/IP轮询它获得的属性.即它的表示是一个可变对象.

编辑:我有一组我需要轮询的设备.

编辑:我需要使用PyQt遍历显示其属性的对象.我知道我可以添加像__getitem__和的特殊方法__iter__,但我想知道是否有更简单的方法.

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

tzo*_*zot 48

Python <3.3

你的意思是这样的?

class Record(object):
    __slots__= "attribute1", "attribute2", "attribute3",

    def items(self):
        "dict style items"
        return [
            (field_name, getattr(self, field_name))
            for field_name in self.__slots__]

    def __iter__(self):
        "iterate over fields tuple/list style"
        for field_name in self.__slots__:
            yield getattr(self, field_name)

    def __getitem__(self, index):
        "tuple/list style getitem"
        return getattr(self, self.__slots__[index])

>>> r= Record()
>>> r.attribute1= "hello"
>>> r.attribute2= "there"
>>> r.attribute3= 3.14

>>> print r.items()
[('attribute1', 'hello'), ('attribute2', 'there'), ('attribute3', 3.1400000000000001)]
>>> print tuple(r)
('hello', 'there', 3.1400000000000001)
Run Code Online (Sandbox Code Playgroud)

请注意,提供的方法只是可能方法的一个示例.

Python≥3.3更新

你可以使用types.SimpleNamespace:

>>> import types
>>> r= types.SimpleNamespace()
>>> r.attribute1= "hello"
>>> r.attribute2= "there"
>>> r.attribute3= 3.14
Run Code Online (Sandbox Code Playgroud)

dir(r)会为你提供属性名称(.startswith("__")当然过滤掉所有).

  • @ u0b34a0f6ae看看SimpleNamespace的实现方式,将它放在`types`中是有意义的.如果你看一下`types`模块中的很多"类",你会注意到它们都是通过使用`type`函数来提取支持特定值的类型(例如`LambdaType = type(lambda:无)`).猜猜SimpleNamespace是如何实现的?`SimpleNamespace = type(sys.implementation)`. (4认同)
  • @ u0b34a0f6ae因为它不是一个集合,所以像`class X():pass`这样的空类不是一个集合.最重要的是,它没有迭代或大小的概念.为什么你认为它应该在`collections`中? (4认同)

Cam*_*ron 18

你有什么理由不能使用普通字典吗?看起来这些属性在您的特定情况下没有特定的顺序.

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

我刚刚找到了"记录"配方,它被描述为可变的命名元组.它们是使用类实现的.

更新:

既然你说顺序对你的场景很重要(并且你想要遍历所有的属性),那么OrderedDict似乎是要走的路.这是collectionsPython 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)
Run Code Online (Sandbox Code Playgroud)

然后你可以这样做:

>>> 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']
Run Code Online (Sandbox Code Playgroud)

  • 如果您需要订购,请尝试OrderedDict.我相信它也在收藏模块中. (3认同)

Abb*_*fei 10

这可以使用空类和它的实例来完成,如下所示:

>>> class a(): pass
... 
>>> ainstance = a()
>>> ainstance.b = 'We want Moshiach Now'
>>> ainstance.b
'We want Moshiach Now'
>>> 
Run Code Online (Sandbox Code Playgroud)


Lei*_*ork 9

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

打包主页:http://pypi.python.org/pypi/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)
Run Code Online (Sandbox Code Playgroud)

简单的默认值示例:

Basis = recordtype('Basis', [('x', 1), ('y', 0)])
Run Code Online (Sandbox Code Playgroud)

遍历以下字段person1:

map(person1.__getattribute__, Person._fields)
Run Code Online (Sandbox Code Playgroud)

  • [namedlist](https://pypi.python.org/pypi/namedlist/1.4)是同一作者的更新包,它支持python 3,并且自2014年起积极开发. (9认同)

Dan*_*iel 9

这个问题很老了,但为了完整起见,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)
Run Code Online (Sandbox Code Playgroud)

attrs 第三方库为 Python 2 和 Python 3 提供了更多功能。如果需求更多地围绕您无法在本地保留的内容而不是专门仅使用 stdlib,那么供应商依赖项也没有什么问题。dephell 有一个很好的帮手可以做到这一点。