Python enclosing scopes

The Python enclosing scopes has a larger scope than the local scopes. The enclosing scope can enclose one or more local scopes. Note enclosing scopes have larger scopes than the local scopes but a smaller region of influence when compared to global scope.

Link :Python local scopes

The program below shows an example of a function having an enclosing scope.

>>> def enclosedFunc(): #this function enclosed the localFunc()
	def localFunc(): #localFunc() region starts here
		print( 'lc=',lc )
		print( 'm'=,m ) #localFunc() region ends here
	localFunc() #Calls the localFunc()
	print( 'In enclosedFunc() m=',m )
	print( '\n',lc )

>>> enclosedFunc()

In enclosedFunc() m=901
Traceback (most recent call last):
  File "<pyshell#16>", line 1, in <module>
  File "<pyshell#15>", line 9, in enclosedFunc
    print( '\n',lc )
NameError: name 'lc' is not defined

Some points to note from the code above:
i)In the code above the ‘enclosedFunc()’ is said to have an enclosed scope over the local scope of ‘localFunc()’ function.
ii)When enclosedFunc() is called, it goes through the code of the localFunc() function. And inside the enclosedFunc() we have called the localFunc(), so that means the localFunc() code is executed first.
iii)Inside the localFunc() we could access the ‘m’ and ‘lc’ variable. But once the scope is outside the localFunc() we cannot access the ‘lc’ variable because it is available only under the localFunc() region, so in trying to access it we get the error message “Traceback… NameError: name ‘lc’ is not defined”.

Since enclosed scopes have influence over the local scope it does not mean the enclosed scopes variable will take over the local scope variable. In local scope, a local variable has more power over the other scopes variable. This means the local variable value will be always preferred in the local scope. Consider the example below.

>>> def OuterFunc():
	def InnerFunc(): #InnerFunc() region starts here***
		var=12345 #same name as the outer variable
		print( var ) #InnerFunc() region ends here****
	InnerFunc() #Calls the InnerFunc()
	print( var )

>>> OuterFunc()

Inside the InnerFunc() printing the ‘var’ value gives the local region value, not the enclosed ‘var'(900) value. So you see the local ‘var’ has more influence in the local region.

Outside the InnerFunc(), we tried to print the value of ‘var’ again, this time the enclosed scope variable value is printed out. This is obvious, as the local region variable has ceased to exist here, so the enclosed variable value is considered.

Link : Python global scopes

More examples

A function enclosing one or more functions

In case a function encloses one or more functions, then each function enclosed by the outer function will have their own local region. Note these local regions are not shared among them.

>>> def OuterFunc():
	def InnerFunc1(): #InnerFunc1() scope begins here
		print( "Under InnerFunc1(), out=",out ) #InnerFUnc1() ends here
	def InnerFunc2(): #InnerFunc2() scope begins here
		print( "\nUnder InnerFunc2(), out= ",out ) #InnerFunc2() ends here
	def InnerFunc3(): #InnerFunc3() scope begins here
		print('\nUnder InnerFunc3(), var=',var )
		print( 'Under InnerFunc3(), out=',out )#InnerFunc3() ends here

>>> OuterFunc()
Under InnerFunc1(), out= 123

Under InnerFunc2(), out=  901

Under InnerFunc3(), var= 77777
Under InnerFunc3(), out= 1000
Out= 901

Under InnerFunc1(), the local ‘out’ value is taken, this is obvious as local variable has more power over other variables.

Under InnerFunc2(), the enclosed variable ‘out’ value is taken. This is due to the fact that the enclosed scope has still influence over the local scope.

Under InnerFunc3(), the value of ‘var’ is 77777, which is the local variable value. The value of the InnerFunc2() ‘var'(789) is not taken. The ‘out’ value in this case, is also the value of the local region not the enclosed one.

Function enclosing another enclosed function

When we have mulitple functions enclosing one another, the scope rule still applies. The local scope variable always have the higher influence. Next to the local scope is the scope enclosing the local scope. After this is the scope enclosing the inner two scopes and so on.

In the code below Outer1() encloses Outer2() which encloses Inner() function.

>>> def Outer1():
	def Outer2(): #Outer2 scope starts here
		def Inner(): #Inner() scope starts here
			print('Inner() m=',m)
			print('Inner() var=',var) #Inner() ends here
		print( '\nOuter2() var=',var ) #Outer2() ends here
	print('Outer1() var=',var)

>>> Outer1()
Inner() m= 111
Inner() var= 90

Outer2() var= 90
Outer1() var= 65

Inside Inner(), the local ‘m'(111) value is taken and not the one outside it. And here, the ‘var’ value taken is that of Outer2() and not that of the Outer1(). Since Outer2() scope is next to the Inner() scope.

Inside Outer2(), the ‘var'(90) is taken and not the Outer1() ‘var'(65). This is obviously because local variable has more power over the enclosing one.

And inside Outer1() the ‘var'(65) is taken, here the Outer2() ‘var’ has ceased to exist.

***Side note

i)Any scopes not belonging to local scopes or global scopes are considered as enclosing scopes.

Always remember,the order followed by Python while looking for names in a scope or namespace is : local socpe> enclosing scope > global scope > built-in scope. This order is also known as ‘LEGB‘.

Link :Python scopes types