Estoy tratando de 'desestructurar' un diccionario y asociar valores con nombres de variables después de sus claves. Algo como
params = {'a':1,'b':2}
a,b = params.values()
Pero dado que los diccionarios no están ordenados, no hay garantía de que params.values()
devuelvan valores en el orden de (a, b)
. ¿Hay alguna forma agradable de hacer esto?
python
sorting
dictionary
hatmatrix
fuente
fuente
let {a, b} = params
. Mejora la legibilidad y está completamente en línea con cualquier Zen del que quieras hablar.let {a: waffles} = params
. Se tarda unos segundos en averiguarlo, incluso si está acostumbrado.Respuestas:
Si tiene miedo de los problemas relacionados con el uso del diccionario local y prefiere seguir su estrategia original, los Diccionarios ordenados de las colecciones Python 2.7 y 3.1.OrderedDicts le permite recuperar los elementos del diccionario en el orden en que se insertaron por primera vez
fuente
from operator import itemgetter params = {'a': 1, 'b': 2} a, b = itemgetter('a', 'b')(params)
En lugar de elaboradas funciones lambda o comprensión de diccionario, también puede utilizar una biblioteca incorporada.
fuente
attrgetter
desde el mismo módulo de biblioteca estándar, que funciona para atributos de objeto (obj.a
). Esta es una distinción importante de JavaScript, dondeobj.a === obj["a"]
.KeyError
, se generará una excepcióna, b = [d[k] for k in ('a','b')]
es mucho más natural / legible (el formulario es mucho más común). Esta sigue siendo una respuesta interesante, pero no es la solución más sencilla.get_id = itemgetter(KEYS)
usar algo así como despuésserial, code, ts = get_id(document)
. Es cierto que debe sentirse cómodo con las funciones de orden superior, pero Python generalmente se siente muy cómodo con ellas. Por ejemplo, consulte los documentos para decoradores como@contextmanager
.Una forma de hacer esto con menos repetición que la sugerencia de Jochen es con una función de ayuda. Esto le da la flexibilidad de enumerar sus nombres de variables en cualquier orden y solo desestructurar un subconjunto de lo que está en el dict:
pluck = lambda dict, *args: (dict[arg] for arg in args) things = {'blah': 'bleh', 'foo': 'bar'} foo, blah = pluck(things, 'foo', 'blah')
Además, en lugar del OrderedDict de joaquin, podría ordenar las claves y obtener los valores. Las únicas capturas son que necesita especificar los nombres de sus variables en orden alfabético y desestructurar todo en el dict:
sorted_vals = lambda dict: (t[1] for t in sorted(dict.items())) things = {'foo': 'bar', 'blah': 'bleh'} blah, foo = sorted_vals(things)
fuente
lambda
a una variable, también puede usar la sintaxis de función normal condef
.itemgetter
desdeoperator
la biblioteca estándar. :)Python solo puede "desestructurar" secuencias, no diccionarios. Por lo tanto, para escribir lo que desee, deberá asignar las entradas necesarias a una secuencia adecuada. Por mi parte, la coincidencia más cercana que pude encontrar es la (no muy sexy):
a,b = [d[k] for k in ('a','b')]
Esto también funciona con generadores:
a,b = (d[k] for k in ('a','b'))
Aquí hay un ejemplo completo:
>>> d = dict(a=1,b=2,c=3) >>> d {'a': 1, 'c': 3, 'b': 2} >>> a, b = [d[k] for k in ('a','b')] >>> a 1 >>> b 2 >>> a, b = (d[k] for k in ('a','b')) >>> a 1 >>> b 2
fuente
¿Quizás de verdad quieres hacer algo como esto?
def some_func(a, b): print a,b params = {'a':1,'b':2} some_func(**params) # equiv to some_func(a=1, b=2)
fuente
Aquí hay otra forma de hacerlo de manera similar a cómo funciona una asignación de desestructuración en JS:
params = {'b': 2, 'a': 1} a, b, rest = (lambda a, b, **rest: (a, b, rest))(**params)
Lo que hicimos fue descomprimir el diccionario de params en valores clave (usando **) (como en la respuesta de Jochen ), luego tomamos esos valores en la firma lambda y los asignamos de acuerdo con el nombre de la clave, y aquí hay una ventaja: nosotros también obtenga un diccionario de lo que no esté en la firma lambda, así que si tuviera:
params = {'b': 2, 'a': 1, 'c': 3} a, b, rest = (lambda a, b, **rest: (a, b, rest))(**params)
Una vez que se haya aplicado la lambda, la variable rest ahora contendrá: {'c': 3}
Útil para omitir claves innecesarias de un diccionario.
Espero que esto ayude.
fuente
prueba esto
d = {'a':'Apple', 'b':'Banana','c':'Carrot'} a,b,c = [d[k] for k in ('a', 'b','c')]
resultado:
a == 'Apple' b == 'Banana' c == 'Carrot'
fuente
Advertencia 1: como se indica en los documentos, no se garantiza que funcione en todas las implementaciones de Python:
Advertencia 2: esta función hace que el código sea más corto, pero probablemente contradice la filosofía de Python de ser lo más explícito posible. Además, no aborda los problemas señalados por John Christopher Jones en los comentarios, aunque podría crear una función similar que funcione con atributos en lugar de claves. ¡Esto es solo una demostración de que puede hacer eso si realmente lo desea!
def destructure(dict_): if not isinstance(dict_, dict): raise TypeError(f"{dict_} is not a dict") # the parent frame will contain the information about # the current line parent_frame = inspect.currentframe().f_back # so we extract that line (by default the code context # only contains the current line) (line,) = inspect.getframeinfo(parent_frame).code_context # "hello, key = destructure(my_dict)" # -> ("hello, key ", "=", " destructure(my_dict)") lvalues, _equals, _rvalue = line.strip().partition("=") # -> ["hello", "key"] keys = [s.strip() for s in lvalues.split(",") if s.strip()] if missing := [key for key in keys if key not in dict_]: raise KeyError(*missing) for key in keys: yield dict_[key]
In [5]: my_dict = {"hello": "world", "123": "456", "key": "value"} In [6]: hello, key = destructure(my_dict) In [7]: hello Out[7]: 'world' In [8]: key Out[8]: 'value'
Esta solución le permite elegir algunas de las claves, no todas, como en JavaScript. También es seguro para los diccionarios proporcionados por el usuario.
fuente
Bueno, si quieres estos en una clase, siempre puedes hacer esto:
class AttributeDict(dict): def __init__(self, *args, **kwargs): super(AttributeDict, self).__init__(*args, **kwargs) self.__dict__.update(self) d = AttributeDict(a=1, b=2)
fuente
Basado en la respuesta de @ShawnFumo, se me ocurrió esto:
def destruct(dict): return (t[1] for t in sorted(dict.items())) d = {'b': 'Banana', 'c': 'Carrot', 'a': 'Apple' } a, b, c = destruct(d)
(Observe el orden de los elementos en dict)
fuente
Dado que los diccionarios son garantiza que los mantendrán su orden de inserción en Python> = 3.7 , eso significa que es completamente seguro e idiomático hacer esto hoy en día:
params = {'a': 1, 'b': 2} a, b = params.values() print(a) print(b)
fuente
b, a = params.values()
, ya que usa orden, no nombres.itemgetter
es la forma más pitónica de hacer esto. Esto no funcionará en Python 3.6 o versiones anteriores y, como depende del orden, puede resultar confuso al principio.No sé si es de buen estilo, pero
locals().update(params)
hará el truco. Luego tiene
a
,b
y lo que estaba en suparams
dictado disponible como variables locales correspondientes.fuente