Grund für globals () in Python?

68

Was ist der Grund dafür, dass globals () in Python funktioniert? Es wird nur ein Wörterbuch globaler Variablen zurückgegeben, die bereits global sind, sodass sie überall verwendet werden können. Ich frage nur aus Neugier und versuche, Python zu lernen.

def F():
    global x
    x = 1

def G():
    print(globals()["x"]) #will return value of global 'x', which is 1

def H():
    print(x) #will also return value of global 'x', which, also, is 1

F()
G()
H()

Ich kann den Punkt hier nicht wirklich sehen? Ich würde es nur brauchen, wenn ich lokale und globale Variablen mit demselben Namen für beide hätte

def F():
    global x
    x = 1

def G():
    x = 5
    print(x) #5
    print(globals()["x"]) #1

F()
G()

Sie sollten jedoch niemals auf das Problem stoßen, zwei Variablen mit demselben Namen zu haben und beide im selben Bereich verwenden zu müssen.


quelle
3
"Sie sollten jedoch niemals auf das Problem stoßen, zwei Variablen mit demselben Namen zu haben und beide im selben Bereich verwenden zu müssen." Ich kann diesem Gedanken nicht folgen. Das ist der ganze Grund für separate Namespaces, dass Sie Variablen mit demselben Namen in verschiedenen Bereichen haben. Wenn Sie mit zwei von ihnen arbeiten, sind doppelte Namen eine natürliche Sache, aber kein Problem, da Sie ihnen ein Präfix voranstellen können.
Michael
Nun, ich komme aus der C ++ - Familie, daher bin ich mir bei Python-Leuten nicht sicher, aber soweit ich mir vorstellen kann, sollten Sie keine globale Variable haben, die keinen eindeutigen Namen hat. Sicher, es wird Variablen mit demselben Namen und demselben Umfang geben, das war ein dummer Satz von mir, aber keine Globals mit denselben Namen wie lokale. Dann würde ich Namespaces für lokale verwenden ... Aber ich weiß nicht, ob Sie das sagen.
6
@ Mahi: globalsist vielleicht etwas irreführend. globals()ist im Wesentlichen das locals()eines Moduls. Das __builtin__Modul kommt dem Globalen am nächsten, das für Ihr gesamtes Programm wirklich global ist . Alles, was Sie diesem Modul hinzufügen, ist überall in allen Namespaces verfügbar.
Martijn Pieters
Hmm, gute Ergänzung, nicht, dass ich es jetzt brauchen würde, aber vielleicht eines Tages ... Danke :)

Antworten:

89

Python bietet dem Programmierer eine Vielzahl von Tools zur Überprüfung der laufenden Umgebung. globals()ist nur eine davon, und es kann in einer Debugging-Sitzung sehr nützlich sein, um zu sehen, welche Objekte der globale Bereich tatsächlich enthält.

Ich bin mir sicher, dass locals()das Grundprinzip das gleiche ist wie das , um die in einer Funktion definierten Variablen anzuzeigen oder dirum den Inhalt eines Moduls oder die Attribute eines Objekts anzuzeigen.

Ich komme aus einem C ++ - Hintergrund und kann verstehen, dass diese Dinge unnötig erscheinen. In einer statisch verknüpften, statisch typisierten Umgebung wären sie es absolut. In diesem Fall ist zur Kompilierungszeit genau bekannt, welche Variablen global sind, welche Mitglieder ein Objekt haben wird und sogar welche Namen von einer anderen Kompilierungseinheit exportiert werden.

In einer dynamischen Sprache sind diese Dinge jedoch nicht festgelegt; Sie können sich je nach Import des Codes oder sogar zur Laufzeit ändern. Zumindest aus diesem Grund kann der Zugriff auf diese Art von Informationen in einem Debugger von unschätzbarem Wert sein.

Ian Clelland
quelle
12
+1. Außerdem kann das von zurückgegebene Wörterbuch globalsgeändert werden (wahrscheinlich eine Funktion, die Experten am besten überlassen bleibt). Ebenfalls relevant dieses Zitat aus ist Dive Into Python „ , um die Verwendung localsund globalsFunktionen können Sie den Wert von beliebigen Variablen dynamisch zu bekommen, als String den Variablennamen bereitstellt. Dies spiegelt die Funktionalität der getattrFunktion, die Sie für den Zugriff beliebige Funktionen dynamisch ermöglicht durch Bereitstellung des Funktionsnamens als Zeichenfolge. "
Steven Rumbalski
1
Nicht zu sagen, dass Ihre Antwort besser war als die anderer, aber für mich war es das. Danke, ich denke, ich muss mich beruhigen und daran denken, dass Python nicht C ++ ist :) Und danke, dass alle anderen auch geantwortet haben, ziemlich viel geklärt.
Das Ändern von Elementen in local () funktioniert normalerweise nicht. Die meisten Python-Funktionen haben kein Diktat für Einheimische. Wenn Sie also local () aufrufen, wird ein Diktat der aktuellen Werte der Einheimischen erstellt. Das Ändern dieses Diktats spiegelt sich nicht in den Einheimischen wider. Es gab Fälle, in denen Funktionen Dinge wie "Importieren * aus xyz" ausführten (nicht mehr zulässig), bei denen Einheimische mit Namen gesetzt wurden, die zur Kompilierungszeit unbekannt waren. Diese Funktionen wurden mit einem tatsächlichen lokalen Diktat kompiliert. Vor langer Zeit hatten alle Funktionen ein tatsächliches lokales Diktat, und sie haben die Notwendigkeit dafür auslaufen lassen. Ich weiß nicht, unter welchen Bedingungen Sie jetzt ein Diktat haben.
Greggo
40

Dies ist auch nützlich, wenn Sie eine Funktion unter Verwendung des Zeichenfolgennamens der Funktion aufrufen müssen. Zum Beispiel:

def foo():
    pass

function_name_as_string = 'foo'

globals()[function_name_as_string]() # foo(). 
Alex Soroka
quelle
Was ist, wenn die Funktion viele Parameter wie def foo (a, b, c = false) hat? Wie würden Sie diese Parameter an globals () übergeben
Kenan
2
@ksooklall Sie übergeben es wie gewohnt an die Funktion: mit können def foo(*args): print("hw", *args)Sie tun: globals()['foo']()oder globals()['foo']('reason', 42)usw.
Tino
8

Sie können das Ergebnis von übergeben globals() und locals()an die eval, execfileund __import__Befehle. Dadurch wird eine eingeschränkte Umgebung geschaffen, in der diese Befehle ausgeführt werden können.

Daher sind diese Funktionen vorhanden, um andere Funktionen zu unterstützen, die von einer Umgebung profitieren, die sich möglicherweise vom aktuellen Kontext unterscheidet. Sie können beispielsweise globals()einige Variablen aufrufen , dann entfernen oder hinzufügen, bevor Sie eine dieser Funktionen aufrufen.

Bryan Oakley
quelle
6

globals()ist nützlich für eval()- wenn Sie Code auswerten möchten, der sich auf Variablen im Gültigkeitsbereich bezieht, werden diese Variablen entweder global oder lokal angezeigt.


Um ein wenig zu erweitern, eval()interpretiert die integrierte Funktion eine Zeichenfolge von Python-Code , die ihr zugewiesen wurde. Die Signatur lautet : eval(codeString, globals, locals), und Sie würden es so verwenden:

def foo():
    x = 2
    y = eval("x + 1", globals(), locals())
    print("y=" + y) # should be 3

Dies funktioniert, da der Interpreter den Wert von xaus dem locals()Diktat der Variablen erhält . Sie können eval natürlich Ihr eigenes Diktat von Variablen zur Verfügung stellen.

Richard Close
quelle
Ich war nicht derjenige, der abstimmte, aber das ergab keinen Sinn. Könnten Sie zum besseren Verständnis einen Beispielcode angeben?
Klar, ich habe meine Antwort erweitert.
Richard Close
1
Ein bisschen komisch und scheint für mich nutzlos, aber vielleicht ist das nur so, weil ich neu in Python bin: P Trotzdem danke
eval("x+1")macht das Gleiche aufgrund seiner Standardparameter; siehehelp(eval)
Greggo
Schauen Sie auch hier nach, wie globals()verwendet werden kann: stackoverflow.com/a/22021058/9024698 .
Ausgestoßener
1

Es kann in 'deklarativem Python' nützlich sein. Zum Beispiel in dem unten FooDefund BarDefwerden verwenden Klassen eine Reihe von Datenstrukturen zu definieren , die dann durch ein Paket als seinen Eingang verwendet werden, oder seine Konfiguration. Dies ermöglicht Ihnen viel Flexibilität bei der Eingabe und Sie müssen keinen Parser schreiben.

# FooDef, BarDef are classes

Foo_one = FooDef("This one", opt1 = False, valence = 3 )
Foo_two = FooDef("The other one", valence = 6, parent = Foo_one )

namelist = []
for i in range(6):
    namelist.append("nm%03d"%i)

Foo_other = FooDef("a third one", string_list = namelist )

Bar_thing = BarDef( (Foo_one, Foo_two), method = 'depth-first')

Beachten Sie, dass diese Konfigurationsdatei eine Schleife verwendet, um eine Liste von Namen zu erstellen, die Teil der Konfiguration von sind Foo_other. Diese Konfigurationssprache verfügt daher über einen sehr leistungsstarken Präprozessor mit einer verfügbaren Laufzeitbibliothek. Wenn Sie beispielsweise ein komplexes Protokoll suchen oder Dinge aus einer Zip-Datei extrahieren und von base64 dekodieren möchten, um Ihre Konfiguration zu generieren (dieser Ansatz wird natürlich nicht empfohlen, wenn die Eingabe möglicherweise von einem stammt nicht vertrauenswürdige Quelle ...)

Das Paket liest die Konfiguration wie folgt:

conf_globals = {}  # make a namespace
# Give the config file the classes it needs
conf_globals['FooDef']= mypkgconfig.FooDef  # both of these are based ...
conf_globals['BarDef']= mypkgconfig.BarDef  # ... on .DefBase

fname = "user.conf"
try:
    exec open(fname) in conf_globals
except Exception:
    ...as needed...
# now find all the definitions in there
# (I'm assuming the names they are defined with are
# significant to interpreting the data; so they
# are stored under those keys here).

defs = {}
for nm,val in conf_globals.items():
    if isinstance(val,mypkgconfig.DefBase):
        defs[nm] = val

globals()Wenn Sie also ein solches Paket verwenden , ist es hilfreich , endlich auf den Punkt zu kommen , wenn Sie eine Reihe von Definitionen prozedural prägen möchten:

for idx in range(20):
    varname = "Foo_%02d" % i
    globals()[varname]= FooDef("one of several", id_code = i+1, scale_ratio = 2**i)

Dies entspricht dem Ausschreiben

Foo_00 = FooDef("one of several", id_code = 1, scale_ratio=1)
Foo_01 = FooDef("one of several", id_code = 2, scale_ratio=2)
Foo_02 = FooDef("one of several", id_code = 3, scale_ratio=4)
... 17 more ...

Ein Beispiel für ein Paket, das seine Eingabe durch Sammeln einer Reihe von Definitionen aus einem Python-Modul erhält, ist PLY (Python-lex-yacc) http://www.dabeaz.com/ply/ - in diesem Fall sind die Objekte meistens funktionsfähig Objekte, aber auch Metadaten aus den Funktionsobjekten (deren Namen, Dokumentzeichenfolgen und Definitionsreihenfolge) sind Teil der Eingabe. Es ist kein so gutes Beispiel für die Verwendung von globals(). Außerdem wird es von der 'Konfiguration' importiert - letztere ist ein normales Python-Skript - und nicht umgekehrt.

Ich habe 'deklaratives Python' für einige Projekte verwendet, an denen ich gearbeitet habe, und hatte Gelegenheit, globals()Konfigurationen für diese zu schreiben. Man könnte sicherlich argumentieren, dass dies auf eine Schwäche in der Art und Weise zurückzuführen ist, wie die Konfigurationssprache entworfen wurde. Gebrauch vonglobals() auf diese Weise führt nicht zu sehr klaren Ergebnissen. Nur Ergebnisse, die möglicherweise einfacher zu pflegen sind als ein Dutzend nahezu identischer Aussagen.

Sie können es auch verwenden, um Variablen innerhalb der Konfigurationsdatei entsprechend ihren Namen eine Bedeutung zu geben:

# All variables above here starting with Foo_k_ are collected
# in Bar_klist
#
foo_k = [ v for k,v in globals().items() if k.startswith('Foo_k_')]
Bar_klist  = BarDef( foo_k , method = "kset")

Diese Methode kann für jedes Python-Modul nützlich sein , das viele Tabellen und Strukturen definiert, um das Hinzufügen von Elementen zu den Daten zu vereinfachen, ohne dass auch die Referenzen gepflegt werden müssen.

Greggo
quelle
0

Es kann auch verwendet werden, um eine Instanz der Klasse 'classname' aus einer Zeichenfolge abzurufen:

class C:
    def __init__(self, x):
        self.x = x
        print('Added new instance, x:', self.x)


def call(str):
    obj = globals()[str](4)
    return obj

c = call('C')
print(c.x)
Bart
quelle
0

Es kann nützlich sein, wenn Sie das gerade erstellte Modul importieren möchten:

a.py.

[...]

def buildModule():
    [...code to build module...]
    return __import__("somemodule")

[...]

b.py.

from a import buildModule

def setup():
   globals()["somemodule"] = buildModule()
Maksym Ganenko
quelle
0

Nicht wirklich. Globale Variablen, über die Python wirklich verfügt, sind Variablen mit Modulbereich.

# a.py
print(globals())

import b
b.tt()
# b.py
def tt():
    print(globals())

laufen python a.py, mindestens zwei Ausgabe von globals()['__name__']ist unterschiedlich.

Code hier in cpython auf Github zeigt es.

roachsinai
quelle