为什么Python不支持loggingtypes,即可变的namedtuple

为什么Python本身不支持loggingtypes? 这是一个具有可变版本的namedtuple的问题。 我可以使用namedtuple._replace 。 但是我需要把这些logging集合到一个集合中,并且由于namedtuple._replace创build了另一个实例,所以我也需要修改这个集合,这个集合很快就变得凌乱了。

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

编辑:我有一套我需要轮询的设备。

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

编辑:我宁愿一个types的属性是固定的(就像他们在我的设备),但是可变的。

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)会为您提供属性名称(当然,会过滤掉所有.startswith("__") )。

有没有什么理由不能使用正规字典? 看起来属性在特定的情况下没有特定的顺序。

另外,你也可以使用一个类实例(它有很好的属性访问语法)。 如果你想避免为每个实例创build一个__dict__你可以使用__slots__

我也刚刚find了“logging”的配方 ,它们被描述为可变的命名元组。 他们是用类来实现的。

更新:

既然你说顺序对你的场景很重要(你想遍历所有的属性) 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'] 

这可以使用一个空的类和它的实例来完成,就像这样:

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

有一个类似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) 

简单的默认值例子:

 Basis = recordtype('Basis', [('x', 1), ('y', 0)]) 

person1的字段:

 map(person1.__getattribute__, Person._fields) 

这个答案重复另一个 。 有一个可变的替代collections.namedtuple – recordclass 。

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

 from recordclass import recordclass Point = recordclass('Point', 'x y') >>> p = Point(1, 2) >>> p Point(x=1, y=2) >>> print(px, py) 1 2 >>> px += 2; py += 3; print(p) Point(x=3, y=5) 

有更完整的例子 (它也包括性能比较)。

在Python中密切相关的可变名称元组的存在? 问题13testing用于比较6个可变替代品与namedtuple

截至2016 1月11日, 最新的namedlist 1.7在Python 2.7和Python 3.5中都通过了所有这些testing它是一个纯Python实现。

根据这些testing的第二个最好的候选者是C类扩展的logging类。 当然,这取决于你的要求是否C扩展是首选的。

有关详细信息,特别是对于testing,请参阅在Python中存在可变名称元组?

基于一段时间内收集的一些有用的技巧,这个“冷冻类”装饰器几乎可以满足所有需求: http ://pastebin.com/fsuVyM45

由于该代码是超过70%的文件和testing,我不会在这里说更多。

这是一个完整的可变的名为我做的,它的行为像一个列表,是完全兼容的。

 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}) 

你可以做这样的dict子类,这是它自己的__dict__ 。 基本概念与ActiveState的AttrDict配方相同,但实现更简单。 结果是比你需要更可变的东西,因为一个实例的属性和它们的值都是可以改变的。 虽然属性没有sorting,但是可以遍历当前的属性和/或它们的值。

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