Cuándo usar un diccionario vs tupla en Python

31

El ejemplo específico en mente es una lista de nombres de archivo y sus tamaños. No puedo decidir si cada elemento de la lista debe tener la forma {"filename": "blabla", "size": 123}, o simplemente ("blabla", 123). Un diccionario me parece más lógico porque acceder al tamaño, por ejemplo, file["size"]es más explicativo que file[1]... pero no estoy seguro. Pensamientos?

clb
fuente
Como anexo, considere desempaquetar tuplas , si le preocupa la legibilidad de las tuplas fname, file_size = file, donde los datos son su tupla anterior, la eliminaría file[1]y la reemplazaría file_size. Por supuesto, esto se basa en una buena documentación.
nlsdfnbch
2
Depende de qué estructura de datos esté construyendo y cómo piensa acceder a ella. (¿por nombre de archivo? ¿por índice? ¿ambos?) ¿Es solo una variable desechable / estructura de datos, o posiblemente agregará otros elementos (/ atributos) así como tamaño? ¿La estructura necesita recordar un orden? ¿Desea ordenar la lista de tamaños o acceder a ella por posición (por ejemplo, "top-n archivos más grandes / más pequeños")? Dependiendo de eso, la "mejor" respuesta podría ser dict, OrderedDict, namedtuple, simple old list o una clase personalizada propia. Necesito más contexto de tu parte.
smci

Respuestas:

78

Yo usaría un namedtuple:

from collections import namedtuple
Filesize = namedtuple('Filesize', 'filename size')
file = Filesize(filename="blabla", size=123)

Ahora puede usar file.sizey file.filenameen su programa, que en mi humilde opinión es la forma más legible. Note namedtuplecrea objetos inmutables como tuplas, y son más livianos que los diccionarios, como se describe aquí .

Doc Brown
fuente
1
Gracias, buena idea, nunca he oído hablar de ellos antes de hoy (soy bastante novato en Python). Pregunta: ¿qué sucede si alguien en otra parte del código también define la misma "clase", posiblemente de manera ligeramente diferente. por ejemplo, en otro archivo fuente, el compañero de trabajo Bob teníaFilesize = namedtuple('Filesize', 'filepath kilobytes')
user949300 el
También puede usar el attrsmódulo muy agradable (puede encontrarlo pipo simplemente buscarlo), que le permite tener comodidades sintácticas muy similares a las de la tupla con nombre, pero puede darle la mutabilidad (pero también puede hacerse inmutable). La principal diferencia funcional es que las attrsclases hechas no se comparan con tuplas simples, como lo hacen las clases namedtuple.
mtraceur
3
@DocBrown Python no tiene concepto de declaraciones. class, defY =todo sólo sobrescribir los usos anteriores. repl.it
Challenger5
@ Challenger5: tienes razón, mi error, por lo que la respuesta correcta es: la última definición cuenta, no hay error del tiempo de ejecución de Python, pero sigue siendo un comportamiento similar al de cualquier otra variable.
Doc Brown
8
Tenga en cuenta que namedtuplees esencialmente una declaración breve para un nuevo tipo con atributos inmutables. Esto significa que la respuesta es efectivamente: "Ni a tupleni a dict, sino a object". +1
jpmc26
18

{"filename": "blabla", "size": 123}, o simplemente ("blabla", 123)

Esta es la vieja pregunta de si codificar su formato / esquema dentro de banda o fuera de banda.

Cambia un poco de memoria para obtener la legibilidad y portabilidad que resulta de expresar el formato de los datos directamente en los datos. Si no lo hace, el conocimiento de que el primer campo es el nombre del archivo y el segundo es el tamaño debe mantenerse en otro lugar. Eso ahorra memoria pero cuesta legibilidad y portabilidad. ¿Qué le costará más dinero a su empresa?

En cuanto al problema inmutable, recuerde que inmutable no significa inútil ante el cambio. Significa que necesitamos obtener más memoria, hacer el cambio en una copia y usar la nueva copia. Eso no es gratis, pero a menudo no es un factor decisivo. Usamos cadenas inmutables para cambiar las cosas todo el tiempo.

Otra consideración es la extensibilidad. Cuando almacena datos solo posicionalmente, sin codificar información de formato, entonces está condenado a una sola herencia, que realmente no es más que la práctica de concatenar campos adicionales después de los campos establecidos. Puedo definir un tercer campo para que sea la fecha de creación y seguir siendo compatible con su formato, ya que defino primero y segundo de la misma manera.

Sin embargo, lo que no puedo hacer es reunir dos formatos definidos de manera independiente que tengan algunos campos superpuestos, algunos no, almacenarlos en un formato y hacer que sean útiles para cosas que solo conocen uno u otro formato.

Para hacer eso, necesito codificar la información de formato desde el principio. Necesito decir "este campo es el nombre del archivo". Hacer eso permite la herencia múltiple.

Probablemente esté acostumbrado a que la herencia solo se exprese en el contexto de los objetos, pero las mismas ideas funcionan para los formatos de datos porque, bueno, los objetos se almacenan en formatos de datos. Es exactamente el mismo problema.

Así que usa lo que creas que es más probable que necesites. Alcanzo la flexibilidad a menos que pueda señalar una buena razón para no hacerlo.

naranja confitada
fuente
3
Para ser honesto, no creo que cualquiera que esté seguro entre utilizando un filtro en banda o fuera de banda formato tiene tales requisitos apretada rendimiento que necesitarían a la necesidad de utilizar un formato fuera de banda
Alexander - Restablecer Mónica
2
@Alexander muy cierto. Prefiero enseñarle a la gente sobre eso para que entiendan lo que están viendo cuando se enfrentan a soluciones fuera de banda. Los formatos binarios a menudo hacen esto por razones de ofuscación. No todos quieren ser portátiles. En cuanto a las razones de rendimiento, si realmente importa, considere la compresión antes de recurrir a fuera de banda.
candied_orange
Recuerde que OP está utilizando Python, por lo que probablemente no estén demasiado preocupados por el rendimiento. La mayoría de los códigos de alto nivel deben escribirse teniendo en cuenta primero la legibilidad; La optimización prematura es la fuente de todos los males.
Dagrooms
@Dagrooms no odia a Python. Funciona bien en muchos casos. Pero por lo demás, estoy de acuerdo con todo lo que dijiste. Mi punto era decir "Esta es la razón por la cual la gente hace eso. Esta es la razón por la que probablemente no te importe".
candied_orange
@CandiedOrange No odio el idioma, lo uso en mi trabajo diario. No me gusta la forma en que la gente lo usa.
Dagrooms
7

Usaría una clase con dos propiedades. file.sizees mejor que cualquiera de los dos file[1]o file["size"].

Simple es mejor que complejo.

JacquesB
fuente
En caso de que alguien se pregunte: para generar JSON, ambos funcionan igual de bien: file = Filesize(filename='stuff.txt', size=222)y filetup = ("stuff.txt", 222)ambos generan el mismo JSON: json.dumps(file)y json.dumps(filetup)resultan en:'["stuff.txt", 222]'
Juha Untinen
5

¿Son únicos los nombres de archivo? Si es así, puede eliminar la lista por completo y simplemente usar un diccionario puro para todos los archivos. por ejemplo (un sitio web hipotético)

{ 
  "/index.html" : 5467,
  "/about.html" : 3425,
  "/css/main.css" : 9876
}

etc ...

Ahora, no obtienes "nombre" y "tamaño", solo usas clave y valor, pero a menudo esto es más natural. YMMV.

Si realmente desea un "tamaño" para mayor claridad, o necesita más de un valor para el archivo, entonces:

{ 
   "/index.html" : { "size": 5467, "mime_type" : "foo" },
   "/about.html" : { "size": 3425, "mime_type" : "foo" }
   "/css/main.css" : { "size": 9876, "mime_type" : "bar" }
}
user949300
fuente
0

En python, el diccionario es un objeto mutable. Por otro lado, la tupla es un objeto inmutable.

Si necesita cambiar la clave del diccionario, par de valores a menudo o siempre. Sugiero diccionario para usar.

Si tiene datos fijos / estáticos, sugiero usar tuplas.

# dictionary define.
a = {}
a['test'] = 'first value'

# tuple define.
b = ()
b = b+(1,)

# here, we can change dictionary value for key 'test'
a['test'] = 'second'

Pero no se pueden cambiar los datos de tupla usando el operador de asignación.

Profundizar Patel
fuente