Ich versuche, ein Wörterbuch zu "zerstören" und den Variablennamen nach seinen Schlüsseln Werte zuzuordnen. Etwas wie
params = {'a':1,'b':2}
a,b = params.values()
Da Wörterbücher jedoch nicht bestellt werden, gibt es keine Garantie dafür, dass params.values()
Werte in der Reihenfolge von zurückgegeben werden (a, b)
. Gibt es eine gute Möglichkeit, dies zu tun?
python
sorting
dictionary
hatmatrix
quelle
quelle
let {a, b} = params
. Es verbessert die Lesbarkeit und stimmt vollständig mit dem Zen überein, über das Sie sprechen möchten.let {a: waffles} = params
. Es dauert einige Sekunden, um es herauszufinden, selbst wenn Sie daran gewöhnt sind.Antworten:
Wenn Sie Angst vor den Problemen bei der Verwendung von den Einheimischen dictionary beteiligt sind und Sie es vorziehen , Ihre ursprüngliche Strategie, bestellten Wörterbücher aus Python 2.7 und 3.1 folgen collections.OrderedDicts ermöglicht es Ihnen , Sie Wörterbuch Elemente in der Reihenfolge wiederherzustellen , in dem sie zuerst eingeführt wurden
quelle
from operator import itemgetter params = {'a': 1, 'b': 2} a, b = itemgetter('a', 'b')(params)
Anstelle von ausgefeilten Lambda-Funktionen oder Wörterbuchverständnis kann auch eine eingebaute Bibliothek verwendet werden.
quelle
attrgetter
aus demselben Standardbibliotheksmodul erweitern, das für Objektattribute (obj.a
) funktioniert . Dies ist ein wesentlicher Unterschied zu JavaScript, woobj.a === obj["a"]
.KeyError
wird eine Ausnahmea, b = [d[k] for k in ('a','b')]
, viel natürlicher / lesbarer (die Form ist viel häufiger). Dies ist immer noch eine interessante Antwort, aber das ist nicht die einfachste Lösung.get_id = itemgetter(KEYS)
spätere Verwendungserial, code, ts = get_id(document)
einfacher. Zugegeben, Sie müssen mit Funktionen höherer Ordnung vertraut sein, aber Python ist im Allgemeinen sehr vertraut mit ihnen. ZB siehe die Dokumente für Dekorateure wie@contextmanager
.Eine Möglichkeit, dies mit weniger Wiederholungen als Jochens Vorschlag zu tun, ist eine Hilfsfunktion. Dies gibt Ihnen die Flexibilität, Ihre Variablennamen in beliebiger Reihenfolge aufzulisten und nur eine Teilmenge der im Diktat enthaltenen Elemente zu zerstören:
pluck = lambda dict, *args: (dict[arg] for arg in args) things = {'blah': 'bleh', 'foo': 'bar'} foo, blah = pluck(things, 'foo', 'blah')
Anstelle von Joaquins OrderedDict können Sie auch die Schlüssel sortieren und die Werte abrufen. Die einzigen Haken sind, dass Sie Ihre Variablennamen in alphabetischer Reihenfolge angeben und alles im Diktat zerstören müssen:
sorted_vals = lambda dict: (t[1] for t in sorted(dict.items())) things = {'foo': 'bar', 'blah': 'bleh'} blah, foo = sorted_vals(things)
quelle
lambda
einer Variablen eine zuweisen möchten, können Sie auch die normale Funktionssyntax mit verwendendef
.itemgetter
ausoperator
der Standardbibliothek implementiert . :)Python kann nur Sequenzen "destrukturieren", keine Wörterbücher. Um zu schreiben, was Sie wollen, müssen Sie die erforderlichen Einträge einer richtigen Reihenfolge zuordnen. Für mich ist das (nicht sehr sexy) am besten passende Spiel:
a,b = [d[k] for k in ('a','b')]
Dies funktioniert auch mit Generatoren:
a,b = (d[k] for k in ('a','b'))
Hier ist ein vollständiges Beispiel:
>>> 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
quelle
Vielleicht möchten Sie wirklich so etwas tun?
def some_func(a, b): print a,b params = {'a':1,'b':2} some_func(**params) # equiv to some_func(a=1, b=2)
quelle
Hier ist eine andere Möglichkeit, dies ähnlich wie bei einer Destrukturierungszuweisung in JS zu tun :
params = {'b': 2, 'a': 1} a, b, rest = (lambda a, b, **rest: (a, b, rest))(**params)
Wir haben das Parameter-Wörterbuch in Schlüsselwerte entpackt (mit **) (wie in Jochens Antwort ), dann haben wir diese Werte in die Lambda-Signatur aufgenommen und sie entsprechend dem Schlüsselnamen zugewiesen - und hier ist ein Bonus - wir Holen Sie sich auch ein Wörterbuch von allem, was nicht in der Unterschrift des Lambda enthalten ist.
params = {'b': 2, 'a': 1, 'c': 3} a, b, rest = (lambda a, b, **rest: (a, b, rest))(**params)
Nachdem das Lambda angewendet wurde, enthält die Restvariable nun: {'c': 3}
Nützlich, um nicht benötigte Schlüssel aus einem Wörterbuch zu entfernen.
Hoffe das hilft.
quelle
Versuche dies
d = {'a':'Apple', 'b':'Banana','c':'Carrot'} a,b,c = [d[k] for k in ('a', 'b','c')]
Ergebnis:
a == 'Apple' b == 'Banana' c == 'Carrot'
quelle
Warnung 1: Wie in den Dokumenten angegeben, funktioniert dies nicht garantiert bei allen Python-Implementierungen:
Warnung 2: Diese Funktion verkürzt den Code zwar, widerspricht jedoch wahrscheinlich der Python-Philosophie, so explizit wie möglich zu sein. Darüber hinaus werden die Probleme, auf die John Christopher Jones in den Kommentaren hingewiesen hat, nicht behandelt, obwohl Sie eine ähnliche Funktion erstellen könnten, die mit Attributen anstelle von Schlüsseln funktioniert. Dies ist nur eine Demonstration, dass Sie das tun können, wenn Sie wirklich wollen!
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'
Mit dieser Lösung können Sie einige der Schlüssel auswählen, nicht alle, wie in JavaScript. Es ist auch sicher für vom Benutzer bereitgestellte Wörterbücher
quelle
Wenn Sie diese in einer Klasse haben möchten, können Sie dies immer tun:
class AttributeDict(dict): def __init__(self, *args, **kwargs): super(AttributeDict, self).__init__(*args, **kwargs) self.__dict__.update(self) d = AttributeDict(a=1, b=2)
quelle
Basierend auf der Antwort von @ShawnFumo habe ich Folgendes gefunden:
def destruct(dict): return (t[1] for t in sorted(dict.items())) d = {'b': 'Banana', 'c': 'Carrot', 'a': 'Apple' } a, b, c = destruct(d)
(Beachten Sie die Reihenfolge der Artikel im Diktat)
quelle
Da Wörterbücher garantiert ihre Einfügereihenfolge in Python> = 3.7 beibehalten , bedeutet dies, dass es heutzutage absolut sicher und idiomatisch ist, dies einfach zu tun:
params = {'a': 1, 'b': 2} a, b = params.values() print(a) print(b)
quelle
b, a = params.values()
, da die Reihenfolge und nicht die Namen verwendet werden.itemgetter
ist der pythonischste Weg, dies zu tun. Dies funktioniert unter Python 3.6 oder niedriger nicht und da es von der Reihenfolge abhängt, kann es zunächst verwirrend sein.Ich weiß nicht, ob es ein guter Stil ist, aber
locals().update(params)
wird den Trick machen. Sie haben dann
a
,b
und was war in Ihrerparams
dict als lokale Variablen entspricht.quelle