Globale Variablen der Python-Funktion?


271

Ich weiß, dass ich aufgrund dieser Verwirrung zunächst die Verwendung globaler Variablen vermeiden sollte. Wenn ich sie jedoch verwenden würde, ist das Folgende ein gültiger Weg, um sie zu verwenden? (Ich versuche, die globale Kopie einer Variablen aufzurufen, die in einer separaten Funktion erstellt wurde.)

x = "somevalue"

def func_A ():
   global x
   # Do things to x
   return x

def func_B():
   x = func_A()
   # Do things
   return x

func_A()
func_B()

Hat das x, was die zweite Funktion verwendet, den gleichen Wert wie die globale Kopie x, die func_averwendet und geändert wird? Ist beim Aufrufen der Funktionen nach der Definition die Reihenfolge wichtig?


1
Achten Sie auch darauf, nicht anzunehmen, dass Python Referenzen vor der Zuweisung als solche behandelt, nur weil Ihnen in Ihrer Funktion eine Variable zugewiesen wurde. Wenn Sie bis zur ersten Zuweisung x verwenden, ist dies nicht die globale oder die lokale Zuweisung. Sie erhalten die berüchtigte UnboundLocalError-Ausnahme in Ihrem Gesicht :)
osirisgothra

Antworten:


412

Wenn Sie einfach auf eine globale Variable zugreifen möchten, verwenden Sie einfach deren Namen. Um den Wert zu ändern , müssen Sie jedoch das globalSchlüsselwort verwenden.

Z.B

global someVar
someVar = 55

Dies würde den Wert der globalen Variablen auf 55 ändern. Andernfalls würde nur einer lokalen Variablen 55 zugewiesen.

Die Reihenfolge der Funktionsdefinitionslisten spielt keine Rolle (vorausgesetzt, sie beziehen sich nicht in irgendeiner Weise aufeinander), die Reihenfolge, in der sie aufgerufen werden.


2
In dem Code, den ich gegeben habe, macht func_B Dinge (1) mit der globalen Kopie von x (wie von func_A erhalten), (2) mit einer lokalen Variablen x mit dem gleichen Wert des Ergebnisses von func_A oder (3) mit eine lokale Variable x ohne Wert und (in den Augen des Compilers) ohne Beziehung zu "einem Wert" oder dem x in func_A?
Akshat Shekhar

xin func_Bist eine lokale Variable, die ihren Wert vom Rückgabewert des Aufrufs an func_A- also denke ich, das würde es zu Ihrem (2) machen
Levon

ok, nehmen wir an, x war eine zufällige Sequenz, die von func_A generiert wurde (dh, dass func_A bei jeder Ausführung ein anderes x erzeugte). Würde das Ausführen des Programms wie geschrieben dazu führen, dass func_b ein anderes x ändert als das, was ursprünglich erzeugt wurde, als func_a war namens? Wenn ja, wie kann ich das beheben?
Akshat Shekhar

1
Ja, wenn func_Adie globale Variable während jedes Laufs geändert und func_Bzur Verwendung zurückgegeben wird, func_Bwird jedes Mal mit einem geänderten Wert gearbeitet. Ich bin mir nicht sicher, wie Sie das Problem beheben können. Möglicherweise möchten Sie die hilfreichste Antwort auf Ihre aktuelle / ursprüngliche Frage akzeptieren und dann eine andere Frage zu einer Frage stellen, die wie eine Folgefrage aussieht.
Levon

1
Eigentlich kommt es darauf an, was x ist. Wenn x unveränderlich ist, bleibt das x in func_B darin, da es lokal deklariert wird, auch wenn sie denselben Wert haben. Dies gilt für Tupel, Ints ... Wenn es sich beispielsweise um eine Instanz einer Liste handelt und Sie dies tun x.append("..."), wird die globale Variable x geändert, da die lokale Variable auf die globale verweist.
Jadkik94

110

Innerhalb eines Python-Bereichs erstellt jede Zuweisung zu einer Variablen, die nicht bereits in diesem Bereich deklariert wurde, eine neue lokale Variable, es sei denn , diese Variable wurde früher in der Funktion als Verweis auf eine Variable mit globalem Gültigkeitsbereich mit dem Schlüsselwort deklariert global.

Schauen wir uns eine modifizierte Version Ihres Pseudocodes an, um zu sehen, was passiert:

# Here, we're creating a variable 'x', in the __main__ scope.
x = 'None!'

def func_A():
  # The below declaration lets the function know that we
  #  mean the global 'x' when we refer to that variable, not
  #  any local one

  global x
  x = 'A'
  return x

def func_B():
  # Here, we are somewhat mislead.  We're actually involving two different
  #  variables named 'x'.  One is local to func_B, the other is global.

  # By calling func_A(), we do two things: we're reassigning the value
  #  of the GLOBAL x as part of func_A, and then taking that same value
  #  since it's returned by func_A, and assigning it to a LOCAL variable
  #  named 'x'.     
  x = func_A() # look at this as: x_local = func_A()

  # Here, we're assigning the value of 'B' to the LOCAL x.
  x = 'B' # look at this as: x_local = 'B'

  return x # look at this as: return x_local

Tatsächlich könnten Sie alles func_Bmit der benannten Variablen umschreiben x_localund es würde identisch funktionieren.

Die Reihenfolge ist nur für die Reihenfolge von Bedeutung, in der Ihre Funktionen Operationen ausführen, die den Wert des globalen x ändern. In unserem Beispiel spielt also die Reihenfolge keine Rolle, da func_BAnrufe func_A. In diesem Beispiel spielt die Reihenfolge eine Rolle:

def a():
  global foo
  foo = 'A'

def b():
  global foo
  foo = 'B'

b()
a()
print foo
# prints 'A' because a() was the last function to modify 'foo'.

Beachten Sie, dass dies globalnur zum Ändern globaler Objekte erforderlich ist. Sie können weiterhin von einer Funktion aus auf sie zugreifen, ohne sie zu deklarieren global. So haben wir:

x = 5

def access_only():
  return x
  # This returns whatever the global value of 'x' is

def modify():
  global x
  x = 'modified'
  return x
  # This function makes the global 'x' equal to 'modified', and then returns that value

def create_locally():
  x = 'local!'
  return x
  # This function creates a new local variable named 'x', and sets it as 'local',
  #  and returns that.  The global 'x' is untouched.

Beachten Sie den Unterschied zwischen create_locally und access_only- darin access_onlybesteht, auf das globale x zuzugreifen, obwohl es nicht aufgerufen wird global, und obwohl create_locallyes auch nicht verwendet wird global, wird eine lokale Kopie erstellt, da ein Wert zugewiesen wird.

Die Verwirrung hier ist, warum Sie keine globalen Variablen verwenden sollten.


2
Ich denke nicht, dass dies in der Praxis sehr verwirrend ist. Sie müssen nur die Regeln für das Scoping von Python verstehen .
Casey Kuball

20

Wie andere angemerkt haben, müssen Sie eine Variable globalin einer Funktion deklarieren, wenn diese Funktion die globale Variable ändern kann. Wenn Sie nur darauf zugreifen möchten, brauchen Sie nichtglobal .

Um etwas näher darauf einzugehen, bedeutet "Ändern" Folgendes: Wenn Sie den globalen Namen neu binden möchten, damit er auf ein anderes Objekt verweist, muss der Name deklariert werdenglobal in der Funktion werden.

Viele Operationen, die ein Objekt ändern (mutieren), binden den globalen Namen nicht erneut, um auf ein anderes Objekt zu verweisen. Sie sind daher alle gültig, ohne den Namen globalin der Funktion zu deklarieren .

d = {}
l = []
o = type("object", (object,), {})()

def valid():     # these are all valid without declaring any names global!
   d[0] = 1      # changes what's in d, but d still points to the same object
   d[0] += 1     # ditto
   d.clear()     # ditto! d is now empty but it`s still the same object!
   l.append(0)   # l is still the same list but has an additional member
   o.test = 1    # creating new attribute on o, but o is still the same object

8

Hier ist ein Fall, der mich auffiel, als ich einen globalen Wert als Standardwert für einen Parameter verwendete.

globVar = None    # initialize value of global variable

def func(param = globVar):   # use globVar as default value for param
    print 'param =', param, 'globVar =', globVar  # display values

def test():
    global globVar
    globVar = 42  # change value of global
    func()

test()
=========
output: param = None, globVar = 42

Ich hatte erwartet, dass param einen Wert von 42 hat. Überraschung. Python 2.7 hat den Wert von globVar ausgewertet, als die Funktion func zum ersten Mal analysiert wurde. Das Ändern des Werts von globVar hatte keine Auswirkungen auf den Standardwert, der param zugewiesen wurde. Das Verzögern der Auswertung, wie im Folgenden, funktionierte so, wie ich es brauchte.

def func(param = eval('globVar')):       # this seems to work
    print 'param =', param, 'globVar =', globVar  # display values

Oder wenn Sie sicher sein wollen,

def func(param = None)):
    if param == None:
        param = globVar
    print 'param =', param, 'globVar =', globVar  # display values

Das erinnerte mich an das Problem , eine leere Liste als Standardwert zuzuweisen . Und wie im Beispiel können Sie anstelle des normalen Vergleichs verwenden , um iszu überprüfen, ob etwas vorhanden ist . None==
berna1111

6

Sie können direkt auf eine globale Variable innerhalb einer Funktion zugreifen. Wenn Sie den Wert dieser globalen Variablen ändern möchten, verwenden Sie "globaler Variablenname". Siehe folgendes Beispiel:

var = 1
def global_var_change():
      global var
      var = "value changed"
global_var_change() #call the function for changes
print var

Im Allgemeinen ist dies keine gute Programmierpraxis. Durch das Unterbrechen der Namespace-Logik kann es schwierig werden, Code zu verstehen und zu debuggen.


2

Sie müssen die verwenden global Deklaration verwenden, wenn Sie den einer globalen Variablen zugewiesenen Wert ändern möchten.

Sie brauchen es nicht, um aus einer globalen Variablen zu lesen. Beachten Sie, dass das Aufrufen einer Methode für ein Objekt (auch wenn dadurch die Daten in diesem Objekt geändert werden) den Wert der Variablen, die dieses Objekt enthält, nicht ändert (keine reflektierende Magie).


2
Diese Formulierung ist unglücklich. In Python ist der einer Variablen zugewiesene Wert eine Referenz, daher ist er technisch korrekt (und ich habe keinen Zweifel, dass Sie das gemeint haben), aber viele Leser interpretieren "Ändern des Werts" möglicherweise als "Mutieren des Objekts", was nicht der Fall ist der Fall - xs.append(xs.pop(0))funktioniert gut ohne global xs.

@delnan Meine Antwort ist sorgfältig formuliert, aber ich werde klarstellen.
Marcin
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.