2012-02-28 11 views
12

en Python si hago lo siguiente:En Python hay algo así como update que es para actualizar lo que se ordena ordenar?

>>> list = [ 3, 2, 1] 
>>> sorted_list = k.sort() 

Entonces sorted_list es None y list se ordena:

>>> sorted_list = k.sort() 
>>> print list, sorted_list 
[1, 2, 3] None 

Sin embargo, si hago lo siguiente:

>>> list = [ 3, 2, 1] 
>>> sorted_list = sorted(list) 

Entonces list permanece sin clasificar y sorted_list contiene una copia de la lista ordenada:

>>> print list, sorted_list 
[3, 2, 1] [1, 2, 3] 

Me pregunto si hay un equivalente para la función update para los diccionarios.

De esa manera podría hacer algo como esto:

def foo(a, b, extra={}): 
    bar = { 'first': a, 'second': b } 
    special_function(**updated(bar, extra)) 
    normal_function(**bar) 

en lugar de tener que hacer algo como esto:

def foo(a, b, extra={}): 
    bar = { 'first': a, 'second': b } 
    special_bar = bar.copy() 
    special_bar.update(extra) # [1] 
    special_function(**special_bar) 
    normal_function(**bar) 

[1] Sí me doy cuenta de que podría simplemente reemplazar estas dos líneas con extra.update(bar), pero supongamos que quiero retener extra como para más adelante en la función.

que se dan cuenta de que podía aplicar esto a mí mismo de esta manera:

def updated(old_dict, extra={}): 
    new_dict = old_dict.copy() 
    new_dict.update(extra) 
    return new_dict 

O el siguiente, muy ilegible comunicado en el lugar:

special_function(**(dict(bar.items()+extra.items()))) 

Pero esperaba que había algo construido en lo que pude ya uso.

+1

Debería * no * usar 'dict' como nombre de variable. También tenga cuidado con los argumentos predeterminados que se pueden cambiar: mejor acceda al hábito de nunca usarlos. –

+1

Tu debería * no * usar 'dict' como nombre de variable, creo que @SvenMarnach significa :) –

+0

@MattLuongo: Gracias. De hecho, dije lo contrario de lo que quise decir. :) –

Respuesta

17

Usted puede simplemente utilizar el incorporado en dict():

updated_dict = dict(old_dict, **extra_dict) 
+11

Tenga en cuenta que esto no funcionará si las claves 'extra_dict' no son cadenas. –

+1

@RikPoggi: Definitivamente debería haber mencionado esto. Para el caso de uso dado en la pregunta, esta restricción no es relevante. –

+0

Wow. Python nunca deja de sorprender! –

6

Si necesita teclas que no son cadenas, se puede utilizar una función como que: (No es tan fea como su "in situ" expresión + funciona para cualquier número de diccionarios)

from itertools import chain # ← credits go to Niklas B. 

def updated(*dicts): 
    return dict(chain(*map(dict.items, dicts))) 

updated({42: 'the answer'}, {1337: 'elite'}) # {42: 'the answer', 1337: 'elite'} 

De lo contrario, la sugerencia de Sven está bien.

Editar: Si está utilizando Python 2.7 o posterior, también se puede utilizar un diccionario por comprensión, como Sven sugerido en los comentarios:

def updated(*dicts): 
    return {k: v for d in dicts for k, v in d.items()} 
+1

+1, me gusta :) Aunque creo que 'sum' para la concatenación de listas es bastante feo, tal vez' itertools.chain' sería un poco más limpio. Para dos dicts es simplemente 'dict (d1.items() + d2.items())' por cierto, que es un poco más legible, IMO. –

+3

Usar 'sum()' para la concatenación de listas no solo es feo, sino que hará que todo O (n^2). ¿Qué tal si usamos algo como '{k: v para d en dicts para k, v en d.items()}'? –

+0

@SvenMarnach ¡Realmente esta es una muy buena idea! Estoy acostumbrado a Python 2.6, así que no siempre uso las características de Python 2.7 ... – Gandaro

4

realmente no ver lo que está mal en el uso de dos líneas, como usted:

new_bar = bar.copy() 
new_bar.update(extra) 

Es limpio y legible.

>>> d = {1:2, 3:4} 
>>> e = {3:9, 5:25} 
>>> f = d.copy() 
>>> f.update(e) 
>>> d 
{1: 2, 3: 4} 
>>> f 
{1: 2, 3: 9, 5: 25} 
>>> e 
{3: 9, 5: 25} 

En tres palabras: Zen of Python.

Para ser más claros: Mi punto es que no reemplazaría esas dos líneas con una función updated() que no proviene de la biblioteca estándar.

Si debía tropezar en una línea de código como:

new_bar = updated(bar, extra) 

me había tienen que realizar un seguimiento de la función hacia abajo para ver lo que hace. No podría confiar en que no sea algo extraño.

El OP también comparó eso con sorted(), pero sorted() tiene una razón de existir, actúa en todo lo que es iterable y lo hace con el sorprendente timsort. En cambio, ¿cuál debería ser el comportamiento de un hipotético updated()? ¿Debería ser un método de clase dict? Realmente no está claro en mi humilde opinión.

Dijo, por lo que uno podría elegir las dos líneas OP, o la solución de Sven, o una comprensión/expresión generadora de dicto, creo que es solo una cuestión de gusto.

+0

Hm, es un estilo de procedimiento, a diferencia de un enfoque funcional como el de Sven o como 'merge' en Ruby:' {1 => 3, 2 => 4} .merge ({4 => 5}) ', que no mutar cualquier cosa –

+0

@Niklas: Entiendo eso, pero parece que el OP está intentando implementar una función 'updated()', mi punto era que no haría eso. Lo expliqué mejor en mi respuesta "actualizada". –

+1

+1. Haz lo obvio y sigue con la vida. – DSM

Cuestiones relacionadas