Ich möchte eine Reihe lokaler Variablen verwenden, die in einer Funktion außerhalb der Funktion definiert sind. Ich übergebe also x=locals()
den Rückgabewert.
Wie kann ich alle in diesem Wörterbuch definierten Variablen in den Namespace außerhalb der Funktion laden, sodass x['variable']
ich anstelle des Zugriffs auf den Wert einfach verwenden kann variable
?
Antworten:
Betrachten Sie die
Bunch
Alternative:class Bunch(object): def __init__(self, adict): self.__dict__.update(adict)
Wenn Sie also ein Wörterbuch haben
d
und auf seine Werte mit der Syntaxx.foo
anstatt mit dem ungeschickten zugreifen (lesen) möchtend['foo']
, tun Sie dies einfachDies funktioniert sowohl innerhalb als auch außerhalb Funktionen - und es ist enorm sauberer und sicherer als Injektion
d
inglobals()
! Erinnern Sie sich an die letzte Zeile aus dem Zen von Python ...:>>> import this The Zen of Python, by Tim Peters ... Namespaces are one honking great idea -- let's do more of those!
quelle
globals().update(locals())
! (Ich Kind, ich Kind)update
: Stattdessen erhalten Siek,v
Paare mitadict.items()
undif type(v) is dict: self.__dict__[k]=Bunch(v)
und dannelse: self.__dict__[k]=v
für alles andere. Sie können wie ein Namespace auf das Ergebnis zugreifen, einschließlich der Zuweisung neuer Werte zu den verschachtelten Bereichen.Anstatt ein eigenes Objekt zu erstellen, können Sie Folgendes verwenden
argparse.Namespace
:from argparse import Namespace ns = Namespace(**mydict)
Um das Gegenteil zu tun:
mydict = vars(ns)
quelle
honking great idea
imargparse
Modul liegt.types.SimpleNamespace
mydict = vars(ns)
sowohl das neue Wörterbuch als auch der ursprüngliche Namespace ausgeführt werden, verweist dies auf dasselbe Objekt ( wenn Sie eines der beiden ändern, wird auch das andere geändert). Tun ,mydict = vars(ns).copy()
das zu vermeiden.Dies ist ein absolut gültiger Fall, um Variablen in einem lokalen Bereich in einen anderen lokalen Bereich zu importieren, solange man weiß, was er / sie tut. Ich habe oft gesehen, dass solcher Code auf nützliche Weise verwendet wird. Ich muss nur vorsichtig sein, um den gemeinsamen globalen Raum nicht zu verschmutzen.
Sie können Folgendes tun:
adict = { 'x' : 'I am x', 'y' : ' I am y' } locals().update(adict) blah(x) blah(y)
quelle
locals()
.Das Importieren von Variablen in einen lokalen Namespace ist ein gültiges Problem und wird häufig in Vorlagen-Frameworks verwendet.
Gibt alle lokalen Variablen einer Funktion zurück:
return locals()
Dann wie folgt importieren:
r = fce() for key in r.keys(): exec(key + " = r['" + key + "']")
quelle
Die Bunch- Antwort ist in Ordnung, aber es fehlt an Rekursion und richtig
__repr__
und__eq__
Ordnung, Funktionen, um zu simulieren, was Sie bereits mit einem Diktat tun können. Der Schlüssel zur Rekursion liegt auch nicht nur in der Rekursion von Diktaten, sondern auch in Listen, sodass Diktate in Listen ebenfalls konvertiert werden.Ich hoffe, dass diese beiden Optionen Ihre Anforderungen erfüllen (möglicherweise müssen Sie die Typprüfungen
__elt()
für komplexere Objekte anpassen ; diese wurden hauptsächlich bei JSON-Importen getestet, also sehr einfache Kerntypen).repr(obj)
gibt zurückBunch({...})
, das in ein äquivalentes Objekt neu interpretiert werden kann.class Bunch(object): def __init__(self, adict): """Create a namespace object from a dict, recursively""" self.__dict__.update({k: self.__elt(v) for k, v in adict.items()}) def __elt(self, elt): """Recurse into elt to create leaf namepace objects""" if type(elt) is dict: return type(self)(elt) if type(elt) in (list, tuple): return [self.__elt(i) for i in elt] return elt def __repr__(self): """Return repr(self).""" return "%s(%s)" % (type(self).__name__, repr(self.__dict__)) def __eq__(self, other): return self.__dict__ == other.__dict__
types.SimpleNamespace
bereits implementiert__repr__
und__eq__
alles, was Sie brauchen , ist eine rekursive zu implementieren__init__
Methode:import types class RecursiveNamespace(types.SimpleNamespace): # def __init__(self, /, **kwargs): # better, but Python 3.8+ def __init__(self, **kwargs): """Create a SimpleNamespace recursively""" self.__dict__.update({k: self.__elt(v) for k, v in kwargs.items()}) def __elt(self, elt): """Recurse into elt to create leaf namepace objects""" if type(elt) is dict: return type(self)(**elt) if type(elt) in (list, tuple): return [self.__elt(i) for i in elt] return elt
Die RecursiveNamespace- Klasse verwendet Schlüsselwortargumente, die natürlich aus einem de-referenzierten Diktat (ex
**mydict
) stammen können.Lassen Sie uns sie jetzt auf die Probe stellen:
adict = {'foo': 'bar', 'baz': [{'aaa': 'bbb', 'ccc': 'ddd'}]} a = Bunch(adict) b = RecursiveNamespace(**adict) print('a:', str(a)) print('b:', str(b)) print('a == b :', str(a == b))
Das Ergebnis ist:
a: Bunch({'foo': 'bar', 'baz': [Bunch({'aaa': 'bbb', 'ccc': 'ddd'})]}) b: RecursiveNamespace(baz=[RecursiveNamespace(aaa='bbb', ccc='ddd')], foo='bar') a == b : True
Obwohl es sich um unterschiedliche Klassen handelt, da beide mit äquivalenten Namespaces initialisiert wurden und ihre
__eq__
Methode nur den Namespace (self.__dict__
) vergleicht, wird beim Vergleich der beiden Namespace-Objekte zurückgegebenTrue
Möglicherweise stellen Sie auch fest, dass ich die
type(self)(...)
Verwendung des Klassennamens anstelle der Verwendung des Klassennamens verwende. Dies hat zwei Vorteile: Erstens kann die Klasse umbenannt werden, ohne dass rekursive Aufrufe aktualisiert werden müssen, und zweitens, wenn die Klasse in eine Unterklasse unterteilt ist, wird eine Rekursion unter Verwendung des Unterklassennamens durchgeführt. Es ist auch der Name, der in__repr__
(type(self).__name__
) verwendet wird.quelle
Verwendet das folgende Snippet (PY2), um einen rekursiven Namespace aus meinen dict (yaml) -Konfigurationen zu erstellen:
class NameSpace(object): def __setattr__(self, key, value): raise AttributeError('Please don\'t modify config dict') def dump_to_namespace(ns, d): for k, v in d.iteritems(): if isinstance(v, dict): leaf_ns = NameSpace() ns.__dict__[k] = leaf_ns dump_to_namespace(leaf_ns, v) else: ns.__dict__[k] = v config = NameSpace() dump_to_namespace(config, config_dict)
quelle
Es gibt immer diese Option, ich weiß nicht, dass es die beste Methode da draußen ist, aber sie funktioniert auf jeden Fall. Angenommen, Typ (x) = dikt
for key, val in x.items(): # unpack the keys from the dictionary to individual variables exec (key + '=val')
quelle
locals().update(x)
.