Pregunta

Leer el Cambios en Python 3.1, Encontré algo ... inesperado:

El sys.version_info tuple es ahora un Llamado Tuple:

Nunca escuché sobre las tuplas nombradas antes, y pensé que los elementos podrían ser indexados por números (como en tuplas y listas) o por claves (como en dicts). Nunca esperé que pudieran ser indexados en ambos sentidos.

Por lo tanto, mis preguntas son:

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

Solución

Las tuplas nombradas son básicamente tipos de objetos livianos y fáciles de crear. Las instancias de tupla nombradas se pueden hacer referencia utilizando la deserencia variable similar a objeto o la sintaxis de tupla estándar. Se pueden usar de manera similar a struct u otros tipos de registro comunes, excepto que son inmutables. Se agregaron en Python 2.6 y Python 3.0, aunque hay un Receta para la implementación en Python 2.4.

Por ejemplo, es común representar un punto como tupla (x, y). Esto lleva al 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 llamada 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 nombradas todavía son compatibles 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

De este modo, Debe usar tuplas nombradas en lugar de tuplas en cualquier lugar donde crea que la notación de objetos hará que su código sea más pitónico y más fácilmente legible. Personalmente, he comenzado a usarlos para representar tipos de valor muy simples, particularmente al pasarlos como parámetros a las funciones. Hace que las funciones sean más legibles, sin ver el contexto del embalaje de tupla.

Es más, También puede reemplazar ordinario inmutable clases que no tienen funciones, solo campos con ellos. Incluso puede usar sus tipos de tupla nombrados como clases base:

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

Sin embargo, como con las tuplas, los atributos en 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 práctica para Registros de registro mutable 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 nombrada" que le permita agregar nuevos campos. Es posible que solo desee usar un diccionario en esta situación. Las tuplas nombradas se pueden convertir en diccionarios usando pt1._asdict() que devuelve {'x': 1.0, 'y': 5.0} y se puede operar con todas las funciones de diccionario habituales.

Como ya se señaló, deberías Verifique la documentación Para obtener más información a partir de la cual se construyeron estos ejemplos.

Otros consejos

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

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)

¿Qué se llaman tuplas?

Una tupla llamada es una tupla.

Hace todo lo que puede una tupla.

Pero es más que una sola tupla.

Es una subclase específica de una tupla que se crea programáticamente en 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 todas partes donde se usa una tupla sin romperse. Esto se conoce como sustituabilidad 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 usar 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 comprender las tuplas nombradas, primero debe saber qué es una tupla. Una tupla es esencialmente una lista inmutable (no se puede cambiar en el lugar en la memoria).

Así es como podrías 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'

Puedes expandir una tupla con iterable desempaquetado:

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

¡Las tuplas nombradas son tuplas que permiten que sus elementos se accedan por nombre en lugar de solo índice!

Haces un tituple de nombre como este:

>>> 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 un poco más legible de la API:

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

¿Cómo usarlos?

Puede hacer todo lo que TUPLE puede hacer (ver arriba) y 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 un script o programa grande, ¿dónde generalmente se define una tupla llamada?

Los tipos que creas con namedtuple son básicamente clases que puedes crear con una corta de taquilla fácil. Trátalos como clases. Defínelos en el nivel del módulo, para que Pickle y otros usuarios puedan encontrarlos.

El ejemplo de trabajo, en el nivel del 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 falla en buscar 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 nombradas en lugar de tuplas normales?

Úselos cuando mejore su código para que se exprese la semántica de los elementos de tupla en su código. Puede usarlos en lugar de un objeto si usa un objeto con atributos de datos sin cambios y sin funcionalidad. Tú también puedes Subclaselos 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 las tuplas nombradas?

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

No hay memoria adicional utilizada por tuplas con nombre versus tuplas.

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

Está buscando un objeto ranurado que implementa toda la funcionalidad de una lista de tamaño estático o una lista subclasiada que funcione como una tupla nombrada (y que de alguna manera bloquea la lista de cambiar de tamaño).

Un ejemplo ahora expandido, y quizás incluso de Liskov, ejemplo 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, simplemente 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

Las TTUPLE son una gran característica, son un contenedor perfecto para los datos. Cuando tenga que "almacenar" datos, utilizaría 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 livianas, pero carecen de legibilidad para una gran cantidad de entradas en los campos de datos.

Las TTUPLE son el compromiso perfecto para los dos enfoques, tienen una gran legibilidad, liviano e inmutabilidad (¡además de que son polimórficos!).

Las tuplas nombradas permiten la compatibilidad hacia atrás con el código que verifica la versión como esta

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

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

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

namedtuple

es una de las formas más fáciles de limpiar su código y hacerlo más legible. Se autodocumenta lo que está sucediendo en la tupla. Las instancias de NameTuples son tan eficientes en la memoria como las tuplas regulares como no tienen diccionarios por instancia, lo que los hace más rápido 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á sucediendo en el primer ejemplo. Con un NameTuple, cada campo tiene un nombre. Y accede por nombre en lugar de posición o índice. En vez de p[1], podemos llamarlo P.Saturación. Es más fácil de entender. Y se ve más limpio.

Crear una instancia de NameTuple 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 acaba de decir, el TamenTuple facilita la comprensión de las tuplas. Entonces, si necesita hacer referencia a los elementos en la tupla, entonces crearlos como llamado Tuples solo tiene sentido.
  2. Además de ser más liviano que un diccionario, NamedTuple también mantiene el orden a diferencia del diccionario.
  3. Como en el ejemplo anterior, es más simple crear una instancia de NamedTuple que diccionario. Y hacer referencia al elemento en la tupla nombrada parece más limpia que un diccionario. p.hue más bien quep['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 Tuple.
  • Field_names: una secuencia de nombres para cada campo. Puede ser una secuencia como en una lista ['x', 'y', 'z'] o cadena x y z (sin comas, solo espacios en blanco) o x, y, z.
  • renombrar: si el cambio de 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 en ['abc', '_1', 'ghi', '_3'], eliminando la palabra clave 'def' (ya que esa es una palabra reservada para definir funciones) y el nombre de campo duplicado 'abc'.
  • demasiado: si es verboso True, la definición de clase se imprime justo antes de ser construido.

Aún puede acceder a Nombres de su posición, si así lo desea. p[1] == p.saturation. Todavía desempaca como una tupla normal.

Métodos

Todos Métodos de tupla regulares son compatibles. Ej: min (), max (), len (), in, no en, concatenación (+), índice, corte, etc. y hay algunos adicionales para NamedTuple. Nota: Todos estos comienzan con un bajo. _replace, _make, _asdict.

_replaceDevuelve una nueva instancia de la tupla nombrada reemplazo de 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 campo no están en citas; Son palabras clave aquí.Recuerda: Las tuplas son inmutables, incluso si se les llaman y tienen el _replace método. los _replace produce un new instancia; No modifica el original ni reemplaza el valor anterior. Por supuesto, puede guardar el nuevo resultado en 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 artículo dentro del paréntesis debería ser el iterable. Por lo tanto, 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 Orden de orden que mapea los 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 nombrada que es similar a la Tuple nombrada pero mutablehttps://pypi.python.org/pypi/namedlist

¿Qué se llamó?

Como su nombre indica, NamedTuple es una tupla con nombre. En la tupla estándar, accedemos a los elementos utilizando el índice, mientras que NamedTuple permite al usuario definir el nombre de los elementos. Esto es muy útil, especialmente los archivos de CSV (valor separado por comas) y trabajar con un conjunto de datos complejo y grande, donde el código se vuelve desordenado con el uso de índices (no tan pitónicos).

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

Lectura

>>>#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 Tuple llamado, se puede usar para crear una definición de clase y tiene todas las características de la tupla original.

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

Otra forma (una nueva forma) de usar Tuple llamado Tuple es usar namedTuple para el paquete de escritura: Escriba sugerencias en namedtuple

Usemos el ejemplo de la respuesta principal en esta publicación para ver cómo usarla.

(1) Antes de usar la tupla nombrada, el código es así:

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)
print(line_length)

(2) Ahora usamos la tupla nombrada

from typing import NamedTuple, Number

heredar la clase NameTuple y defina el nombre de la variable en la nueva clase. La prueba es el nombre de la clase.

class test(NamedTuple):
x: Number
y: Number

crear instancias de la clase y asignarles valores

pt1 = test(1.0, 5.0)   # x is 1.0, and y is 5.0. The order matters
pt2 = test(2.5, 1.5)

Use las variables de las instancias para calcular

line_length = sqrt((pt1.x-pt2.x)**2 + (pt1.y-pt2.y)**2)
print(line_length)

Prueba esto:

collections.namedtuple()

Básicamente, namedtuples son fáciles de crear, tipos de objetos livianos. Convierten los tuplas en contenedores convenientes para tareas simples. Con namedtuples, no tiene que usar índices enteros para acceder a los 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 de definir un 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'

Como para 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'
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top