Próbuję „zniszczyć” słownik i skojarzyć wartości z nazwami zmiennych po kluczach. Coś jak
params = {'a':1,'b':2}
a,b = params.values()
Ale ponieważ słowniki nie są uporządkowane, nie ma gwarancji, że params.values()
zwrócą wartości w kolejności (a, b)
. Czy jest na to dobry sposób?
python
sorting
dictionary
hatmatrix
źródło
źródło
let {a, b} = params
. Poprawia czytelność i jest całkowicie zgodny z każdym Zenem, o którym chcesz rozmawiać.let {a: waffles} = params
. Rozumienie tego zajmuje kilka sekund, nawet jeśli jesteś do tego przyzwyczajony.Odpowiedzi:
Jeśli obawiasz się problemów związanych z korzystaniem z lokalnego słownika i wolisz podążać za swoją oryginalną strategią, Uporządkowane słowniki z kolekcji Pythona 2.7 i 3.1.OrderedDicts umożliwia odzyskanie pozycji ze słownika w kolejności, w jakiej zostały wstawione po raz pierwszy
źródło
from operator import itemgetter params = {'a': 1, 'b': 2} a, b = itemgetter('a', 'b')(params)
Zamiast rozbudowanych funkcji lambda lub rozumienia ze słownika, równie dobrze można użyć wbudowanej biblioteki.
źródło
attrgetter
z tego samego standardowego modułu biblioteki, który działa dla atrybutów obiektu (obj.a
). Jest to główna różnica w stosunku do JavaScript, gdzieobj.a === obj["a"]
.KeyError
wyjątek zostanie podniesionya, b = [d[k] for k in ('a','b')]
jest o wiele bardziej naturalny / czytelny (forma jest o wiele bardziej powszechna). To wciąż interesująca odpowiedź, ale nie jest to najprostsze rozwiązanie.get_id = itemgetter(KEYS)
użyć czegoś podobnego do późniejszegoserial, code, ts = get_id(document)
. Trzeba przyznać, że musisz czuć się komfortowo z funkcjami wyższego rzędu, ale Python ogólnie bardzo dobrze sobie z nimi radzi. Np. Zobacz dokumentację dla dekoratorów, takich jak@contextmanager
.Jednym ze sposobów na zrobienie tego z mniejszą liczbą powtórzeń niż sugestia Jochena jest użycie funkcji pomocniczej. Daje to elastyczność, aby wyświetlić nazwy zmiennych w dowolnej kolejności i zniszczyć tylko podzbiór tego, co jest w dyktandzie:
pluck = lambda dict, *args: (dict[arg] for arg in args) things = {'blah': 'bleh', 'foo': 'bar'} foo, blah = pluck(things, 'foo', 'blah')
Ponadto zamiast OrderedDict joaquina można posortować klucze i uzyskać wartości. Jedyne złapanie polega na tym, że musisz podać nazwy zmiennych w porządku alfabetycznym i zniszczyć wszystko w dyktandzie:
sorted_vals = lambda dict: (t[1] for t in sorted(dict.items())) things = {'foo': 'bar', 'blah': 'bleh'} blah, foo = sorted_vals(things)
źródło
lambda
zmienną a, równie dobrze możesz użyć normalnej składni funkcjidef
.itemgetter
zoperator
w standardowej bibliotece. :)Python jest w stanie „zniszczyć” tylko sekwencje, a nie słowniki. Aby więc napisać, co chcesz, będziesz musiał odwzorować potrzebne wpisy w odpowiedniej kolejności. Jeśli chodzi o mnie, najbliższe dopasowanie, jakie mogłem znaleźć, to (niezbyt seksowne):
a,b = [d[k] for k in ('a','b')]
Działa to również z generatorami:
a,b = (d[k] for k in ('a','b'))
Oto pełny przykład:
>>> 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
źródło
Może naprawdę chcesz zrobić coś takiego?
def some_func(a, b): print a,b params = {'a':1,'b':2} some_func(**params) # equiv to some_func(a=1, b=2)
źródło
Oto inny sposób, aby zrobić to podobnie do tego, jak działa przydział destrukturyzujący w JS:
params = {'b': 2, 'a': 1} a, b, rest = (lambda a, b, **rest: (a, b, rest))(**params)
To, co zrobiliśmy, to rozpakowanie słownika parametrów na wartości kluczy (używając **) (jak w odpowiedzi Jochena ), a następnie wzięliśmy te wartości w sygnaturze lambda i przypisaliśmy je zgodnie z nazwą klucza - i oto bonus - my zdobądź także słownik wszystkiego, czego nie ma w sygnaturze lambdy, więc gdybyś miał:
params = {'b': 2, 'a': 1, 'c': 3} a, b, rest = (lambda a, b, **rest: (a, b, rest))(**params)
Po zastosowaniu lambdy pozostała zmienna będzie teraz zawierać: {'c': 3}
Przydatne do pomijania niepotrzebnych kluczy ze słownika.
Mam nadzieję że to pomoże.
źródło
Spróbuj tego
d = {'a':'Apple', 'b':'Banana','c':'Carrot'} a,b,c = [d[k] for k in ('a', 'b','c')]
wynik:
a == 'Apple' b == 'Banana' c == 'Carrot'
źródło
Ostrzeżenie 1: jak stwierdzono w dokumentacji, nie ma gwarancji, że będzie to działać na wszystkich implementacjach Pythona:
Ostrzeżenie 2: ta funkcja skraca kod, ale prawdopodobnie jest sprzeczna z filozofią Pythona polegającą na byciu tak jednoznacznym, jak to tylko możliwe. Co więcej, nie rozwiązuje problemów wskazanych przez Johna Christophera Jonesa w komentarzach, chociaż możesz stworzyć podobną funkcję, która będzie działać z atrybutami zamiast kluczy. To tylko demonstracja, że możesz to zrobić, jeśli naprawdę chcesz!
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'
To rozwiązanie pozwala na wybranie niektórych kluczy, a nie wszystkich, jak w JavaScript. Jest również bezpieczny dla słowników dostarczanych przez użytkowników
źródło
Cóż, jeśli chcesz je mieć na zajęciach, zawsze możesz to zrobić:
class AttributeDict(dict): def __init__(self, *args, **kwargs): super(AttributeDict, self).__init__(*args, **kwargs) self.__dict__.update(self) d = AttributeDict(a=1, b=2)
źródło
Na podstawie odpowiedzi @ShawnFumo wymyśliłem to:
def destruct(dict): return (t[1] for t in sorted(dict.items())) d = {'b': 'Banana', 'c': 'Carrot', 'a': 'Apple' } a, b, c = destruct(d)
(Zwróć uwagę na kolejność pozycji w dyktandzie)
źródło
Ponieważ słowniki gwarantują zachowanie kolejności wstawiania w Pythonie> = 3.7 , oznacza to, że obecnie jest to całkowicie bezpieczne i idiomatyczne:
params = {'a': 1, 'b': 2} a, b = params.values() print(a) print(b)
źródło
b, a = params.values()
, ponieważ używa kolejności, a nie nazw.itemgetter
to najbardziej pythonowy sposób na zrobienie tego. To nie zadziała w Pythonie 3.6 lub starszym, a ponieważ zależy od kolejności, na początku może być mylące.Nie wiem, czy to dobry styl, ale
locals().update(params)
da rade. Masz wtedy wszystko
a
,b
co było w twoimparams
dyktandzie, dostępne jako odpowiednie zmienne lokalne.źródło