sirve - ¿Por qué Python no admite el tipo de registro?(es decir, nombre mutuable mutable)
que se puede hacer con python (9)
¿Por qué Python no admite un tipo de registro de forma nativa? Es una cuestión de tener una versión mutable de namedtuple.
Podría usar namedtuple._replace
. Pero necesito tener estos registros en una colección y, dado que namedtuple._replace
crea otra instancia, también necesito modificar la colección, que se desordena rápidamente.
Antecedentes: tengo un dispositivo cuyos atributos debo obtener al sondearlo a través de TCP / IP. Es decir, su representación es un objeto mutable.
Edición: tengo un conjunto de dispositivos para los que necesito hacer una encuesta.
Editar: necesito recorrer el objeto que muestra sus atributos usando PyQt. Sé que puedo agregar métodos especiales como __getitem__
y __iter__
, pero quiero saber si hay una manera más fácil.
Edición: preferiría un tipo cuyos atributos sean fijos (como en mi dispositivo), pero son mutables.
Python <3.3
¿Quieres decir algo como esto?
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)
Tenga en cuenta que los métodos proporcionados son solo una muestra de los métodos posibles.
Python ≥3.3 actualización
Puedes usar types.SimpleNamespace
:
>>> import types
>>> r= types.SimpleNamespace()
>>> r.attribute1= "hello"
>>> r.attribute2= "there"
>>> r.attribute3= 3.14
dir(r)
le proporcionará los nombres de los atributos (filtrando todos los .startswith("__")
, por supuesto).
¿En la existencia estrechamente relacionada de tupla nombrada mutable en Python? Las preguntas de la pregunta 13 se utilizan para comparar 6 alternativas mutables a un namedtuple
.
La última lista namedlist 1.7 passes todas estas pruebas con Python 2.7 y Python 3.5 a partir del 11 de enero de 2016. Es una implementación pura de Python.
El segundo mejor candidato según estas pruebas es el recordclass
que es una extensión de C. Por supuesto, depende de sus requisitos si una extensión C es preferida o no.
Para más detalles, especialmente para las pruebas, consulte ¿ Existencia de tupla nombrada mutable en Python?
¿Hay alguna razón por la que no pueda usar un diccionario regular? Parece que los atributos no tienen un orden específico en su situación particular.
Alternativamente, también puede usar una instancia de clase (que tiene una buena sintaxis de acceso a atributos). Puede usar __slots__
si desea evitar que se __dict__
un __dict__
para cada instancia.
También acabo de encontrar una receta para los "registros" , que se describen como tuplas nombradas mutables. Se implementan utilizando clases.
Actualizar:
Ya que dice que el orden es importante para su escenario (y que desea recorrer todos los atributos) un OrderedDict
parece ser el camino a seguir. Esto es parte del módulo de collections
estándar de Python 2.7; Hay otras implementations flotan en Internet para Python <2.7.
Para agregar acceso de estilo de atributo, puede subclasificarlo así:
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)
Entonces puedes hacer:
>>> 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'']
Aquí hay una lista completa mutable que hice, que se comporta como una lista y es totalmente compatible con ella.
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})
Basado en varios trucos útiles recopilados a lo largo del tiempo, este decorador "frozenclass" hace prácticamente todo lo necesario: http://pastebin.com/fsuVyM45
Dado que ese código tiene más del 70% de documentación y pruebas, no diré más aquí.
Esta respuesta duplica otra . Hay una alternativa mutable a collections.namedtuple
- recordclass .
Tiene la misma API y huella de memoria como se namedtuple
(en realidad también es más rápido) Es compatible con las tareas. Por ejemplo:
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)
Hay un example más completo (también incluye comparaciones de rendimiento).
Esto se puede hacer usando una clase vacía e instancias de ella, como esta:
>>> class a(): pass
...
>>> ainstance = a()
>>> ainstance.b = ''We want Moshiach Now''
>>> ainstance.b
''We want Moshiach Now''
>>>
Hay una biblioteca similar a namedtuple, pero mutable, llamada recordtype.
Página principal del paquete: http://pypi.python.org/pypi/recordtype
Ejemplo simple:
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)
Ejemplo de valor predeterminado simple:
Basis = recordtype(''Basis'', [(''x'', 1), (''y'', 0)])
Iterar a través de los campos de person1
en orden:
map(person1.__getattribute__, Person._fields)
Podrías hacer algo como esta subclase de dict
que es su propio __dict__
. El concepto básico es el mismo que el de la receta ActiveState AttrDict , pero la implementación es más simple. El resultado es algo más mutable de lo que necesita, ya que tanto los atributos de una instancia como sus valores son modificables. Aunque los atributos no están ordenados, puede iterar a través de los actuales y / o sus valores.
class Record(dict):
def __init__(self, *args, **kwargs):
super(Record, self).__init__(*args, **kwargs)
self.__dict__ = self