The built-in functions globals()
and locals()
returns the global and local symbols table respectively. Python interpreter maintains a data structure containing information about each identifier appearing in the program's source code. This information is about the type, value, scope level, and location of an identifier (also called symbol).
Compiler/interpreter uses these symbol tables for various purposes such as:
- store tall entities so that they can be retrieved efficiently.
- verify if an object has been declared.
- determine the scope of an object.
- type checking and semantic accuracy.
Python interpreter uses the dictionary object to hold this information.
As mentioned above, the symbols may be variables, functions, and classes etc.
Such collection of symbols available to the interpreter at the module level (Python's interactive console is also treated to be at module level) is stored in a dictionary returned by the globals()
function.
Consider the following example:
>>> num1=100
>>> num2=200
>>> name="TutorialsTeacher"
>>> def add(x,y):
z=x+y
return z
>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>,
'__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'num1': 100, 'num2': 200,
'add': <function add at 0x000001E63FBE1AF8>, 'name': 'TutorialsTeacher'}
At module level and inside interactive shell environment, the locals()
function also returns the same dictionary.
>>> locals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>,
'__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'num1': 100, 'num2': 200,
'add': <function add at 0x000001E63FBE1AF8>, 'name': 'TutorialsTeacher'}
Let's check what these functions return from within a function by modifying the add()
function as follows:
>>> def add(x,y):
z=x+y
print ('global symbol table:', globals())
print ('local symbol table:', locals())
return z
>>> add(num1, num2)
global symbol table: {'__name__': '__main__', '__doc__': None, '__package__': None,
'__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None,
'__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>,
'num1': 100, 'num2': 200, 'add': <function add at 0x000001E63FBD15E8>, 'name': 'TutorialsTeacher'}
local symbol table: {'x': 100, 'y': 200, 'z': 300}
As you can see, the global symbol table remains the same. However, when the add()
function is called by passing num1
and num2
, their values are assigned to formal argument variables x
and y
, which are local to the add()
function.
Hence the local table is updated with x
, y
and z
.
Note that if a variable that is already present in global scope is declared in a local scope of a function as well, the compiler gives priority in the local scope. Further, change of its value inside function doesn't affect it in the global space.
x=10
def myfunction():
x=10
x=x*2
print ('x inside function: ', x)
myfunction()
print ('x in global scope: ',x)
x inside function: 20
x in global scope: 10
We can modifying the global variables using the globals()
dictionary, as shown below.
x=10
def myfunction():
x=globals()['x']
x=x*2
globals()['x']=x
print ('global variable x inside function: ',x)
return
myfunction()
print ('global variable x in global scope: ',x)
global variable x inside function: 20
global variable x in global scope: 20
Python also has a global
keyword. It allows a globally declared variable to be used and modified inside a function, ensuring that the modifications are reflected globally as well.
x=10
def myfunction():
global x
x=x*2
print ('global variable x inside function: ',x)
return
myfunction()
print ('global variable x in global scope: ',x)
global variable x inside function: 20
global variable x in global scope: 20
In a situation of nested functions, variables present in the outer function's namespace can be used in the inner function by declaring global.
def outer():
x1 = 15
print ('in outer function:',x1)
def inner():
global x1
x1 = 30
print ('value inside function',x1)
inner()
print("After inner function: ", x1)
outer()
print("value of x1",x1)
in outer function: 15
value inside function 30
After inner function: 15
value of x1 30
Python also has the nolocal
keyword that allows a variable declared in global (outer space).
def outer(isnolocal):
x2=100
print ('value in outer function:',x2)
def withnolocal():
nonlocal x2
x2=50
def withoutnolocal():
x2=50
if isnolocal==True:
withnolocal()
else:
withoutnolocal()
return x2
print (outer(True))
print (outer(False))
value in outer function: 100
50
value in outer function: 100
100
Above, the outer()
function has two nested functions. Both try to modify a variable declared in the outer function. We can see that the inner function withnolocal
having nolocal x2
declaration can modify the outer variable x2
, but changes inside the withoutnolocal()
without nolocal
are not reflected.