Seite 1 von 1

Wie findet der Zugriff auf Referenzen statt?

Verfasst: Montag 9. Juli 2012, 10:40
von template
Hallo zusammen,

ich habe ein Verhalten in Python welches ich nicht verstehe.

Code: Alles auswählen

#!/usr/bin/env python
THISISAGLOBAL = 25

def func1():
	print THISISAGLOBAL

def func2():
	THISISAGLOBAL = 30
	print THISISAGLOBAL

def func3():
	global THISISAGLOBAL
	THISISAGLOBAL = 30
	print THISISAGLOBAL
	
def func4():
	global THISISAGLOBAL

	if 1 == 0:
		THISISAGLOBAL = ISNOTEXECUTED
	print THISISAGLOBAL

def func5():
	if 1 == 0:
		locals()['THISISAGLOBAL'] = ISNOTEXECUTED
	print THISISAGLOBAL
	
def func6():
	if 1 == 0:
		THISISAGLOBAL = 1
	print THISISAGLOBAL

	
func1()
func2()
func1()
func3()
func1()
func4()
func5()
func6()
Der Code liefert hierbei folgende ausgabe:

Code: Alles auswählen

25
30
25
30
30
30
30
Traceback (most recent call last):
  File "./globaltest.py", line 41, in ?
    func6()
  File "./globaltest.py", line 31, in func6
    print THISISAGLOBAL
UnboundLocalError: local variable 'THISISAGLOBAL' referenced before assignment
Ich dachte nun eigentlich, dass der Identifier immer zuerst in den locals gesucht wird und wenn er hier nicht gefunden wird in den globals. Nun hat aber die, nicht durchlaufene, Zuweisung in func6 anscheinend zur Konsequenz, das der Zugriff auf THISISAGLOBAL hier nicht mehr bei den globals versucht wird. Warum?

Vielen herzlichen dank im voraus
template

Re: Wie findet der Zugriff auf Referenzen statt?

Verfasst: Montag 9. Juli 2012, 10:54
von cofi
In `func6` wird dein "global" auch als local benutzt und damit als local betrachtet, da die Zuweisung aber nicht ausgefuehrt wird, bleibt der Name ungebunden.

Und hier noch ein Fall, der dir fehlt:

Code: Alles auswählen

In [1]: GLOB = 23

In [2]: def func7():
   ...:     print GLOB
   ...:     GLOB = 5
   ...:     

In [3]: func7()
---------------------------------------------------------------------------
UnboundLocalError                         Traceback (most recent call last)
<ipython-input-3-2664cf86600a> in <module>()
----> 1 func7()

<ipython-input-2-315cea9167d1> in func7()
      1 def func7():
----> 2     print GLOB
      3     GLOB = 5
      4 

UnboundLocalError: local variable 'GLOB' referenced before assignment
Hier koennte man sagen, dass das doch kein Problem sein sollte, aber wie schon oben erwaehnt: GLOB wird als local betrachtet und damit gibt es `GLOB` vor der Zuweisung nicht.

Re: Wie findet der Zugriff auf Referenzen statt?

Verfasst: Montag 9. Juli 2012, 11:01
von BlackJack
@template: Wenn *irgendwo* innerhalb der Funktion eine Zuweisung an einen Namen geschieht, dann ist der Name lokal, ausser man deklariert ihn mit ``global`` als Modulglobal. Diese Entscheidung geschieht schon beim Übersetzen des Quelltextes und nicht erst bei der Ausführung.

Re: Wie findet der Zugriff auf Referenzen statt?

Verfasst: Montag 9. Juli 2012, 11:36
von cofi
Ergaenzend hierzu der Bytecode:

Code: Alles auswählen

In [1]: import dis

In [2]: def func7():
    print GLOB
    GLOB = 5
   ...:     

In [3]: dis.dis(func7)
  2           0 LOAD_FAST                0 (GLOB)
              3 PRINT_ITEM          
              4 PRINT_NEWLINE       

  3           5 LOAD_CONST               1 (5)
              8 STORE_FAST               0 (GLOB)
             11 LOAD_CONST               0 (None)
             14 RETURN_VALUE        

In [4]: def func1():
   ...:             print THISISAGLOBAL
   ...:     

In [5]: dis.dis(func1)        
  2           0 LOAD_GLOBAL              0 (THISISAGLOBAL)
              3 PRINT_ITEM          
              4 PRINT_NEWLINE       
              5 LOAD_CONST               0 (None)
              8 RETURN_VALUE  

Re: Wie findet der Zugriff auf Referenzen statt?

Verfasst: Dienstag 10. Juli 2012, 08:26
von template
Vielen dank für die ausführlichen Erklärungen. Jetzt hab ichs kappiert. Ich hatte mich immer auf die Grundregel gestellt, das Python-Code "durchlaufen" werden muss, um einfluss auf den Ablauf zu haben, aber wie ich jetzt gelernt habe, gibt es auch ausnahmen von der Regel. :)