ordereddict how example dict create python tuples namedtuple

how - namedtuple python 3 example



¿Qué son las “tuplas con nombre” en Python? (10)

Leyendo los cambios en Python 3.1 , encontré algo ... inesperado:

La tupla sys.version_info ahora es una tupla con nombre :

Nunca antes había oído hablar de tuplas con nombre, y pensé que los elementos podían indexarse ​​por números (como en tuplas y listas) o por claves (como en dados). Nunca esperé que pudieran ser indexados en ambos sentidos.

Así, mis preguntas son:

  • ¿Cómo se llaman las tuplas?
  • ¿Cómo usarlos?
  • ¿Por qué / cuándo debo usar tuplas con nombre en lugar de tuplas normales?
  • ¿Por qué / cuándo debo usar tuplas normales en lugar de tuplas con nombre?
  • ¿Hay algún tipo de "lista nombrada" (una versión mutable de la tupla nombrada)?

¿Cómo se llaman las tuplas?

Una tupla nombrada es una tupla.

Hace todo lo que una tupla puede.

Pero es más que solo una tupla.

Es una subclase específica de una tupla que se crea mediante programación según su especificación, con campos con nombre y una longitud fija.

Esto, por ejemplo, crea una subclase de tupla y, aparte de ser de longitud fija (en este caso, tres), se puede usar en cualquier lugar donde se use una tupla sin romperse. Esto se conoce como sustituibilidad de Liskov:

>>> from collections import namedtuple >>> class_name = ''ANamedTuple'' >>> fields = ''foo bar baz'' >>> ANamedTuple = namedtuple(class_name, fields)

Esto lo instancia

>>> ant = ANamedTuple(1, ''bar'', [])

Podemos inspeccionarlo y utilizar sus atributos:

>>> ant ANamedTuple(foo=1, bar=''bar'', baz=[]) >>> ant.foo 1 >>> ant.bar ''bar'' >>> ant.baz.append(''anything'') >>> ant.baz [''anything'']

Explicación más profunda

Para entender las tuplas nombradas, primero debe saber qué es una tupla. Una tupla es esencialmente una lista inmutable (no se puede cambiar in situ en la memoria).

Así es como puedes usar una tupla regular:

>>> student_tuple = ''Lisa'', ''Simpson'', ''A'' >>> student_tuple (''Lisa'', ''Simpson'', ''A'') >>> student_tuple[0] ''Lisa'' >>> student_tuple[1] ''Simpson'' >>> student_tuple[2] ''A''

Puede expandir una tupla con el desempaquetado iterable:

>>> first, last, grade = student_tuple >>> first ''Lisa'' >>> last ''Simpson'' >>> grade ''A''

¡Las tuplas con nombre son tuplas que permiten acceder a sus elementos por nombre en lugar de solo índice!

Haces un timbre llamado así:

>>> from collections import namedtuple >>> Student = namedtuple(''Student'', [''first'', ''last'', ''grade''])

También puede usar una sola cadena con los nombres separados por espacios, un uso ligeramente más legible de la API:

>>> Student = namedtuple(''Student'', ''first last grade'')

¿Cómo usarlos?

Puede hacer todo lo que pueden hacer las tuplas (ver más arriba), así como hacer lo siguiente:

>>> named_student_tuple = Student(''Lisa'', ''Simpson'', ''A'') >>> named_student_tuple.first ''Lisa'' >>> named_student_tuple.last ''Simpson'' >>> named_student_tuple.grade ''A'' >>> named_student_tuple._asdict() OrderedDict([(''first'', ''Lisa''), (''last'', ''Simpson''), (''grade'', ''A'')]) >>> vars(named_student_tuple) OrderedDict([(''first'', ''Lisa''), (''last'', ''Simpson''), (''grade'', ''A'')]) >>> new_named_student_tuple = named_student_tuple._replace(first=''Bart'', grade=''C'') >>> new_named_student_tuple Student(first=''Bart'', last=''Simpson'', grade=''C'')

Un comentarista preguntó:

En una secuencia de comandos o programa grande, ¿dónde se suele definir una tupla con nombre?

Los tipos que creas con namedtuple son básicamente clases que puedes crear con una taquigrafía sencilla. Trátalos como a las clases. Defínalos en el nivel del módulo, para que Pickle y otros usuarios puedan encontrarlos.

El ejemplo de trabajo, a nivel de módulo global:

>>> from collections import namedtuple >>> NT = namedtuple(''NT'', ''foo bar'') >>> nt = NT(''foo'', ''bar'') >>> import pickle >>> pickle.loads(pickle.dumps(nt)) NT(foo=''foo'', bar=''bar'')

Y esto demuestra la falta de búsqueda de la definición:

>>> def foo(): ... LocalNT = namedtuple(''LocalNT'', ''foo bar'') ... return LocalNT(''foo'', ''bar'') ... >>> pickle.loads(pickle.dumps(foo())) Traceback (most recent call last): File "<stdin>", line 1, in <module> _pickle.PicklingError: Can''t pickle <class ''__main__.LocalNT''>: attribute lookup LocalNT on __main__ failed

¿Por qué / cuándo debo usar tuplas con nombre en lugar de tuplas normales?

Utilícelos cuando mejore su código para que la semántica de los elementos de la tupla se expresen en su código. Puede usarlos en lugar de un objeto si de otro modo usaría un objeto con atributos de datos invariables y sin funcionalidad. También puede subclasificarlos para agregar funcionalidad, por ejemplo :

class Point(namedtuple(''Point'', ''x y'')): """adding functionality to a named tuple""" __slots__ = () @property def hypot(self): return (self.x ** 2 + self.y ** 2) ** 0.5 def __str__(self): return ''Point: x=%6.3f y=%6.3f hypot=%6.3f'' % (self.x, self.y, self.hypot)

¿Por qué / cuándo debo usar tuplas normales en lugar de tuplas con nombre?

Probablemente sería una regresión cambiar de usar tuplas con nombre a tuplas. La decisión de diseño inicial se centra en si el costo del código adicional involucrado merece la legibilidad mejorada cuando se utiliza la tupla.

No hay memoria extra utilizada por las tuplas nombradas frente a las tuplas.

¿Hay algún tipo de "lista nombrada" (una versión mutable de la tupla nombrada)?

Está buscando un objeto ranurado que implemente toda la funcionalidad de una lista de tamaño estático o una lista de subclases que funcione como una tupla con nombre (y que de alguna manera bloquee la lista para que no cambie de tamaño).

Un ejemplo ahora expandido, y quizás incluso sustituible por Liskov, del primero:

from collections import Sequence class MutableTuple(Sequence): """Abstract Base Class for objects that work like mutable namedtuples. Subclass and define your named fields with __slots__ and away you go. """ __slots__ = () def __init__(self, *args): for slot, arg in zip(self.__slots__, args): setattr(self, slot, arg) def __repr__(self): return type(self).__name__ + repr(tuple(self)) # more direct __iter__ than Sequence''s def __iter__(self): for name in self.__slots__: yield getattr(self, name) # Sequence requires __getitem__ & __len__: def __getitem__(self, index): return getattr(self, self.__slots__[index]) def __len__(self): return len(self.__slots__)

Y para usar, solo subclase y defina __slots__ :

class Student(MutableTuple): __slots__ = ''first'', ''last'', ''grade'' # customize >>> student = Student(''Lisa'', ''Simpson'', ''A'') >>> student Student(''Lisa'', ''Simpson'', ''A'') >>> first, last, grade = student >>> first ''Lisa'' >>> last ''Simpson'' >>> grade ''A'' >>> student[0] ''Lisa'' >>> student[2] ''A'' >>> len(student) 3 >>> ''Lisa'' in student True >>> ''Bart'' in student False >>> student.first = ''Bart'' >>> for i in student: print(i) ... Bart Simpson A


namedtuple

es una de las maneras más fáciles de limpiar su código y hacerlo más legible. Auto-documenta lo que está sucediendo en la tupla. Las instancias de Namedtuples son tan eficientes en memoria como las tuplas normales, ya que no tienen diccionarios por instancia, lo que las hace más rápidas que los diccionarios.

from collections import namedtuple Color = namedtuple(''Color'', [''hue'', ''saturation'', ''luminosity'']) p = Color(170, 0.1, 0.6) if p.saturation >= 0.5: print "Whew, that is bright!" if p.luminosity >= 0.5: print "Wow, that is light"

Sin nombrar cada elemento en la tupla, se leería así:

p = (170, 0.1, 0.6) if p[1] >= 0.5: print "Whew, that is bright!" if p[2]>= 0.5: print "Wow, that is light"

Es mucho más difícil entender lo que está pasando en el primer ejemplo. Con un timbre nombrado, cada campo tiene un nombre. Y accedes a él por nombre en lugar de posición o índice. En lugar de p[1] , podemos llamarlo psaturation. Es más fácil de entender. Y se ve más limpio.

Crear una instancia del grupo nombrado es más fácil que crear un diccionario.

# dictionary >>>p = dict(hue = 170, saturation = 0.1, luminosity = 0.6) >>>p[''hue''] 170 #nametuple >>>from collections import namedtuple >>>Color = namedtuple(''Color'', [''hue'', ''saturation'', ''luminosity'']) >>>p = Color(170, 0.1, 0.6) >>>p.hue 170

¿Cuándo podrías usar namedtuple?

  1. Como se acaba de decir, la pareja nombrada facilita mucho la comprensión de las tuplas. Por lo tanto, si necesita hacer referencia a los elementos en la tupla, entonces crearlos como timbres nombrados simplemente tiene sentido.
  2. Además de ser más ligero que un diccionario, nameduuple también mantiene el orden a diferencia del diccionario.
  3. Como en el ejemplo anterior, es más sencillo crear una instancia de se nombra un tupla que un diccionario. Y hacer referencia al elemento en la tupla con nombre se ve más limpio que un diccionario. p.hue lugar de p[''hue''] .

La sintaxis

collections.namedtuple(typename, field_names[, verbose=False][, rename=False])

  • namedtuple está en la biblioteca de colecciones.
  • typename: este es el nombre de la nueva subclase de tupla.
  • field_names: una secuencia de nombres para cada campo. Puede ser una secuencia como en una lista [''x'', ''y'', ''z''] o cadena xyz (sin comas, solo espacios en blanco) o x, y, z .
  • renombrar: si cambiar el nombre es True , los nombres de campo no válidos se reemplazan automáticamente con nombres posicionales. Por ejemplo, [''abc'', ''def'', ''ghi'',''abc''] se convierte a [''abc'', ''_1'', ''ghi'', ''_3''] , eliminando la palabra clave ''def'' (ya que es una palabra reservada para definir funciones) y el nombre de campo duplicado ''abc'' .
  • verbose: si verbose es True , la definición de la clase se imprime justo antes de construirse.

Aún puede acceder a timbres nombrados por su posición, si así lo desea. p[1] == p.saturation . Todavía se desempaqueta como una tupla normal.

Métodos

Todos los métodos regulares de la tupla son compatibles. Ej .: min (), max (), len (), in, not in, concatenation (+), index, slice, etc. Y hay algunos adicionales para nameduuple. Nota: todos estos comienzan con un guión bajo. _replace , _make , _asdict .

_replace Devuelve una nueva instancia de la tupla con nombre que reemplaza los campos especificados con nuevos valores.

La sintaxis

somenamedtuple._replace(kwargs)

Ejemplo

>>>from collections import namedtuple >>>Color = namedtuple(''Color'', [''hue'', ''saturation'', ''luminosity'']) >>>p = Color(170, 0.1, 0.6) >>>p._replace(hue=87) Color(87, 0.1, 0.6) >>>p._replace(hue=87, saturation=0.2) Color(87, 0.2, 0.6)

Aviso : Los nombres de los campos no están entre comillas; son palabras clave aquí. Recuerde : las tuplas son inmutables, incluso si se nombran como tuplas y tienen el método _replace . El _replace produce una new instancia; no modifica el original ni reemplaza el valor anterior. Por supuesto, puede guardar el nuevo resultado a la variable. p = p._replace(hue=169)

_make

Hace una nueva instancia de una secuencia existente o iterable.

La sintaxis

somenamedtuple._make(iterable)

Ejemplo

>>>data = (170, 0.1, 0.6) >>>Color._make(data) Color(hue=170, saturation=0.1, luminosity=0.6) >>>Color._make([170, 0.1, 0.6]) #the list is an iterable Color(hue=170, saturation=0.1, luminosity=0.6) >>>Color._make((170, 0.1, 0.6)) #the tuple is an iterable Color(hue=170, saturation=0.1, luminosity=0.6) >>>Color._make(170, 0.1, 0.6) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 15, in _make TypeError: ''float'' object is not callable

¿Qué pasó con el último? El elemento dentro del paréntesis debe ser el iterable. Así que una lista o tupla dentro del paréntesis funciona, pero la secuencia de valores sin encerrar como un iterable devuelve un error.

_asdict

Devuelve un nuevo OrderedDict que asigna nombres de campo a sus valores correspondientes.

La sintaxis

somenamedtuple._asdict()

Ejemplo

>>>p._asdict() OrderedDict([(''hue'', 169), (''saturation'', 0.1), (''luminosity'', 0.6)])

Referencia : https://www.reddit.com/r/Python/comments/38ee9d/intro_to_namedtuple/

También hay una lista de nombres que es similar a una tupla llamada pero mutable https://pypi.python.org/pypi/namedlist


¿Cuál es el nombre de tu pareja?

Como su nombre lo indica, namedtuple es una tupla con nombre. En la tupla estándar, accedemos a los elementos utilizando el índice, mientras que nameduuple permite al usuario definir el nombre de los elementos. Esto es muy útil, especialmente para procesar archivos csv (valores separados por comas) y trabajar con conjuntos de datos grandes y complejos, donde el código se vuelve desordenado con el uso de índices (no tan pitón).

¿Cómo usarlos?

>>>from collections import namedtuple >>>saleRecord = namedtuple(''saleRecord'',''shopId saleDate salesAmout totalCustomers'') >>> >>> >>>#Assign values to a named tuple >>>shop11=saleRecord(11,''2015-01-01'',2300,150) >>>shop12=saleRecord(shopId=22,saleDate="2015-01-01",saleAmout=1512,totalCustomers=125)

Leyendo

>>>#Reading as a namedtuple >>>print("Shop Id =",shop12.shopId) 12 >>>print("Sale Date=",shop12.saleDate) 2015-01-01 >>>print("Sales Amount =",shop12.salesAmount) 1512 >>>print("Total Customers =",shop12.totalCustomers) 125

Escenario interesante en el procesamiento de CSV:

from csv import reader from collections import namedtuple saleRecord = namedtuple(''saleRecord'',''shopId saleDate totalSales totalCustomers'') fileHandle = open("salesRecord.csv","r") csvFieldsList=csv.reader(fileHandle) for fieldsList in csvFieldsList: shopRec = saleRecord._make(fieldsList) overAllSales += shopRec.totalSales; print("Total Sales of The Retail Chain =",overAllSales)


En Python, en el interior hay un buen uso del contenedor llamado tupla con nombre, se puede usar para crear una definición de clase y tiene todas las características de la tupla original.

El uso de la tupla con nombre se aplicará directamente a la plantilla de clase predeterminada para generar una clase simple, este método permite que una gran cantidad de código mejore la legibilidad y también es muy conveniente al definir una clase.


Prueba esto:

collections.namedtuple()

Básicamente, los namedtuples son fáciles de crear, tipos de objetos ligeros. Convierten las tuplas en contenedores convenientes para tareas simples. Con namedtuples , no tiene que usar índices enteros para acceder a miembros de una tupla.

Ejemplos:

Código 1:

>>> from collections import namedtuple >>> Point = namedtuple(''Point'',''x,y'') >>> pt1 = Point(1,2) >>> pt2 = Point(3,4) >>> dot_product = ( pt1.x * pt2.x ) +( pt1.y * pt2.y ) >>> print dot_product 11

Código 2:

>>> from collections import namedtuple >>> Car = namedtuple(''Car'',''Price Mileage Colour Class'') >>> xyz = Car(Price = 100000, Mileage = 30, Colour = ''Cyan'', Class = ''Y'') >>> print xyz Car(Price=100000, Mileage=30, Colour=''Cyan'', Class=''Y'') >>> print xyz.Class Y


Todos los demás ya lo han respondido, pero creo que todavía tengo algo más que agregar.

Namedtuple podría considerarse intuitivamente como un atajo para definir una clase.

Ver una forma engorrosa y convencional para definir una class .

class Duck: def __init__(self, color, weight): self.color = color self.weight = weight red_duck = Duck(''red'', ''10'') In [50]: red_duck Out[50]: <__main__.Duck at 0x1068e4e10> In [51]: red_duck.color Out[51]: ''red''

En cuanto a namedtuple

from collections import namedtuple Duck = namedtuple(''Duck'', [''color'', ''weight'']) red_duck = Duck(''red'', ''10'') In [54]: red_duck Out[54]: Duck(color=''red'', weight=''10'') In [55]: red_duck.color Out[55]: ''red''


las tuplas con nombre permiten la compatibilidad con el código que comprueba la versión como esta

>>> sys.version_info[0:2] (3, 1)

mientras que permite que el código futuro sea más explícito usando esta sintaxis

>>> sys.version_info.major 3 >>> sys.version_info.minor 1


nameduuples son una gran característica, son un contenedor perfecto para datos. Cuando tenga que "almacenar" datos, usará tuplas o diccionarios, como:

user = dict(name="John", age=20)

o:

user = ("John", 20)

El enfoque del diccionario es abrumador, ya que los dict son mutables y más lentos que las tuplas. Por otro lado, las tuplas son inmutables y ligeras, pero carecen de legibilidad para un gran número de entradas en los campos de datos.

Los dos nombres son el compromiso perfecto para los dos enfoques, tienen una gran legibilidad, ligereza e inmutabilidad (además de que son polimórficos).


namedtuple es una función de fábrica para hacer una clase de tupla. Con esa clase podemos crear tuplas que también pueden llamarse por su nombre.

import collections #Create a namedtuple class with names "a" "b" "c" Row = collections.namedtuple("Row", ["a", "b", "c"], verbose=False, rename=False) row = Row(a=1,b=2,c=3) #Make a namedtuple from the Row class we created print row #Prints: Row(a=1, b=2, c=3) print row.a #Prints: 1 print row[0] #Prints: 1 row = Row._make([2, 3, 4]) #Make a namedtuple from a list of values print row #Prints: Row(a=2, b=3, c=4)


Las tuplas con nombre son básicamente tipos de objetos livianos y fáciles de crear. Se puede hacer referencia a las instancias de tuplas con nombre mediante la eliminación de referencias a variables similares a objetos o la sintaxis de tuplas estándar. Se pueden usar de forma similar a la struct u otros tipos de registros comunes, excepto que son inmutables. Se agregaron en Python 2.6 y Python 3.0, aunque hay una receta para su implementación en Python 2.4 .

Por ejemplo, es común representar un punto como una tupla (x, y) . Esto conduce a un código como el siguiente:

pt1 = (1.0, 5.0) pt2 = (2.5, 1.5) from math import sqrt line_length = sqrt((pt1[0]-pt2[0])**2 + (pt1[1]-pt2[1])**2)

Usando una tupla nombrada se vuelve más legible:

from collections import namedtuple Point = namedtuple(''Point'', ''x y'') pt1 = Point(1.0, 5.0) pt2 = Point(2.5, 1.5) from math import sqrt line_length = sqrt((pt1.x-pt2.x)**2 + (pt1.y-pt2.y)**2)

Sin embargo, las tuplas con nombre aún son compatibles hacia atrás con las tuplas normales, por lo que lo siguiente seguirá funcionando:

Point = namedtuple(''Point'', ''x y'') pt1 = Point(1.0, 5.0) pt2 = Point(2.5, 1.5) from math import sqrt # use index referencing line_length = sqrt((pt1[0]-pt2[0])**2 + (pt1[1]-pt2[1])**2) # use tuple unpacking x1, y1 = pt1

Por lo tanto, debe usar tuplas con nombre en lugar de tuplas en cualquier lugar donde piense que la notación de objetos hará que su código sea más sintético y más legible . Personalmente, comencé a usarlos para representar tipos de valores muy simples, particularmente cuando los pasé como parámetros a funciones. Hace que las funciones sean más legibles, sin ver el contexto del empaque de la tupla.

Además, también puedes reemplazar clases ordinarias inmutables que no tienen funciones , solo campos con ellas. Incluso puedes usar tus tipos de tuplas con nombre como clases base:

class Point(namedtuple(''Point'', ''x y'')): [...]

Sin embargo, al igual que con las tuplas, los atributos de las tuplas nombradas son inmutables:

>>> Point = namedtuple(''Point'', ''x y'') >>> pt1 = Point(1.0, 5.0) >>> pt1.x = 2.0 AttributeError: can''t set attribute

Si desea poder cambiar los valores, necesita otro tipo. Hay una receta útil para tipos de registro mutables que le permiten establecer nuevos valores en atributos.

>>> from rcdtype import * >>> Point = recordtype(''Point'', ''x y'') >>> pt1 = Point(1.0, 5.0) >>> pt1 = Point(1.0, 5.0) >>> pt1.x = 2.0 >>> print(pt1[0]) 2.0

Sin embargo, no conozco ninguna forma de "lista con nombre" que le permita agregar nuevos campos. Es posible que desee utilizar un diccionario en esta situación. Las tuplas nombradas se pueden convertir a diccionarios usando pt1._asdict() que devuelve {''x'': 1.0, ''y'': 5.0} y se puede operar con todas las funciones habituales del diccionario.

Como ya se indicó, debe consultar la documentación para obtener más información a partir de la cual se construyeron estos ejemplos.