Python global keyword -
i confused global keyword behavior in below code snippet, expecting 30, 30, 30 in 3 prints.
def outer_function(): #global ###commented intentionally = 20 def inner_function(): global = 30 print('a =',a) inner_function() print('a =',a) = 10 outer_function() print('a =',a) #output: #30 #20 #expecting 30 here #30
all confusion coming "global a" after outer function definition. understanding @ point of time " reference , assignment variable become globally reflected on declaration of global keyword on variable". if uncommenting 1st global statemnet getting expected o/p 30,30,30.
why global declaration inside inner_function , value change not reflect on 2nd print i:e outer_function(or outer scope), whereas got reflected in global namespace.
please me clarify confusion. (i might sound foolish pythonista out there don't want/deserve downvote here)
a common acronym familiar legb:
- local
- enclosed
- global
- built-in
this order in python search namespaces find variable assignments.
local
the local namespace happens within current code block. function definitions contain local variables first thing found when python looks variable reference. here, python in local scope of foo
first, find x
assignment of 2
, print that. of happens despite x
being defined in global namespace.
x = 1 def foo(): x = 2 print(x) foo() # prints: 2
when python compiles function, decides whether each of variables within definition code block local or global variables. why important? let's take @ same definition of foo
, flip 2 lines inside of it. result can surprising
x = 1 def foo(): print(x) x = 2 foo() # raises: unboundlocalerror: local variable 'x' referenced before assignment
this error occurs because python compiles x
local variable within foo
due assignment of x = 2
.
what need remember local variables can access inside of own scope.
enclosed
when defining multi-layered function, variables not compiled local search values in next highest namespace. here simple example.
x = 0 def outer_0(): x = 1 def outer_1(): def inner(): print(x) inner() outer_1() outer_0() # print: 1
when inner()
compiled, python sets x
global variable, meaning try access other assignments of x
outside of local scope. order in python searches value of x in moving upward through enclosing namespaces. x
not contained in namespace of outer_1
, checks outer_0
, finds values , uses assignment x
within inner
.
x --> inner --> outer_1 --> outer_0 [ --> global, not reached in example]
you can force variable not local using keywords nonlocal
, global
(note: nonlocal
available in python 3). these directives compiler variable scope.
nonlocal
using nonlocal
keyword tells python assign variable first instance found moves upward through namespaces. changes made variable made in variable's original namespace well. in example below, when 2
assigned x
, setting value of x
in scope of outer_0
well.
x = 0 def outer_0(): x = 1 def outer_1(): def inner(): nonlocal x print('inner :', x) x = 2 inner() outer_1() print('outer_0:', x) outer_0() # prints: inner : 1 outer_0: 2
global
the global namespace highest level namespace program running in. highest enclosing namespace function definitions. in general not practice pass values in , out of variables in global namespace unexpected side effects can occur.
global
using global
keyword similar non-local, instead of moving upward through namespace layers, only searches in global namespace variable reference. using same example above, in case declaring global x
tells python use assignment of x
in global namespace. here global namespace has x = 0
:
x = 0 def outer_0(): x = 1 def outer_1(): def inner(): global x print('inner :', x) inner() outer_1() outer_0() # prints: 0
similarly, if variable not yet defined in global namespace, raise error.
def foo(): z = 1 def bar(): global z print(z) bar() foo() # raises: nameerror: name 'z' not defined
built-in
last of all, python check built-in keywords. native python functions such list
, int
final reference python checks after checking variables. can overload native python functions (but please don't this, bad idea).
here example of should not do. in dumb
overload the native python list
function assigning 0
in scope of dumb
. in even_dumber
, when try split string list of letters using list
, python find reference list
in enclosing namespace of dumb
, try use that, raising error.
def dumb(): list = 0 def even_dumber(): x = list('abc') print(x) even_dumber() dumb() # raises: typeerror: 'int' object not callable
you can original behavior referencing global definition of list
using:
def dumb(): list = [1] def even_dumber(): global list x = list('abc') print(x) even_dumber() dumb() # returns: ['a', 'b', 'c']
but again, not this, bad coding practice.
i hope helps bring light of how namespaces work in python. if want more information, chapter 7 of fluent python luciano ramalho has wonderful in-depth walkthrough of namespaces , closures in python.
Comments
Post a Comment