为什么Python不支持记录类型?(即可变命名元组)
为什么Python不原生支持记录类型呢?这其实是因为我们需要一个可变版本的namedtuple。
我可以使用namedtuple._replace
,但是我需要把这些记录放在一个集合里。因为namedtuple._replace
会创建一个新的实例,所以我还得修改这个集合,这样就会变得很麻烦。
背景: 我有一个设备,我需要通过TCP/IP来获取它的属性,也就是说,它的表现形式是一个可变的对象。
编辑: 我有一组设备需要进行轮询。
编辑:
我需要遍历这个对象,显示它的属性,使用的是PyQt。我知道可以添加一些特殊的方法,比如__getitem__
和__iter__
,但我想知道有没有更简单的方法。
编辑: 我更希望有一种类型,它的属性是固定的(就像我设备里的那样),但又是可变的。
11 个回答
这可以通过创建一个空的类和它的实例来实现,像这样:
>>> class a(): pass
...
>>> ainstance = a()
>>> ainstance.b = 'We want Moshiach Now'
>>> ainstance.b
'We want Moshiach Now'
>>>
你有没有想过为什么不直接用普通的字典呢?在你的情况中,属性似乎并没有特定的顺序。
另外,你也可以使用类的实例(这样访问属性会更方便)。如果你想避免为每个实例创建一个 __dict__
,可以使用 __slots__
。
我还发现了一个关于“记录”的示例,它们被描述为可变的命名元组。这个实现是通过类来完成的。
更新:
既然你说顺序对你的情况很重要(而且你想遍历所有属性),那么 OrderedDict
似乎是个不错的选择。这个在 Python 2.7 的标准 collections
模块中就有;在 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']
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)
请注意,这里提供的方法只是一些可能的方法示例。
Python ≥3.3 更新
你可以使用 types.SimpleNamespace
:
>>> import types
>>> r= types.SimpleNamespace()
>>> r.attribute1= "hello"
>>> r.attribute2= "there"
>>> r.attribute3= 3.14
dir(r)
会给你提供属性名称(当然会过滤掉所有以 .__
开头的内容)。