avatarOliver S

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

3787

Abstract

{x}</span>"</span>)</pre></div><h1 id="06fa">Built-in Scope</h1><p id="914d">The built-in scope is the widest scope, and contains all built-in keywords, which you can use anywhere in your code without importing or defining them. A list of Python keywords can be found <a href="https://www.w3schools.com/python/python_ref_keywords.asp">here</a>.</p><h1 id="666d">Modifying Variables of Different Scopes.</h1><p id="03d3">Above explanations were probably quite easy to read and understand — however, things get a little bit more complicated, when wanting to modify variables of different scopes. So far, we used them read-only.</p><h2 id="7e8e">Writing Global Variables</h2><p id="7c64">Consider the following code:</p><div id="f219"><pre>x = <span class="hljs-number">10</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">foo</span>(): x = <span class="hljs-number">20</span> <span class="hljs-built_in">print</span>(<span class="hljs-string">f"Value of x inside foo: <span class="hljs-subst">{x}</span>"</span>)

foo() <span class="hljs-built_in">print</span>(<span class="hljs-string">f"Value of x outside foo: <span class="hljs-subst">{x}</span>"</span>)</pre></div><p id="a44a">This prints:</p><div id="8c25"><pre>Value of x inside foo: <span class="hljs-number">20</span> Value of x outside foo: <span class="hljs-number">10</span></pre></div><p id="985d">Potentially not what you expected — although <code>x</code> is changed to 20 inside <code>foo</code>, this does not reflect outside. The reason is that variables created inside a function are local by default — i.e. a new variable <code>x</code> with value 20 is created inside <code>foo</code>. Also trying something like <code>x += 10</code> would raise <code>UnboundLocalError: local variable ‘x’ referenced before assignment</code> — as in this case <code>x</code> is correctly identified as a global variable, but we cannot modify it by default. For this, we can use the <code>global</code> keyword, afterwards causing both prints to be 20:</p><div id="48ce"><pre>x = <span class="hljs-number">10</span>

<span class="hljs-keyword">def</span> <span class="hljs-title function_">foo</span>(): <span class="hljs-keyword">global</span> x x = <span class="hljs-number">20</span> <span class="hljs-built_in">print</span>(<span class="hljs-string">f"Value of x inside foo: <span class="hljs-subst">{x}</span>"</span>)

foo() <span class="hljs-built_in">print</span>(<span class="hljs-string">f"Value of x outside foo: <span class="hljs-subst">{x}</span>"</span>)</pre></div><p id="f095"><b>Modifying Mutable Objects</b></p><p id="fd19">To complicate things a little further, things change when working with <a href="https://www.guru99.com/mutable-and-immutable-in-python.html#:~:text=Mutable%20in%20Python%20can%20be,store%20a%20collection%20of%20data.">mutable objects</a>, such as lists. What we discussed above, i.e. the no-write access for global variables from within a function, actually only forbids the direct assignment (<code>x = …</code>). However, as we have read access to the object, we can also call functions using it — and in particular modify the contents!</p><p id="ad37">This code works for example without the <code>global</code> keyword, for this reason:</p><div id="a459"><pre>x = [<span class="hljs-number">0</span>, <span class="hljs-number">1</span>]

<span class="hljs-keyword">def</span> <span class="hljs-title function_">foo</span>(): x.append(<span class="hljs-number">2</span>) <span class="hljs-built_in">print</span>(<span class="hljs-string">f"Value of x inside foo: <span class="hljs-subst">{x}</span>"</span>)

foo() <span class="hljs-built_in">print</span>(<span class="hljs-string">f"Value of x outside foo: <span class="hljs-subst">

Options

{x}</span>"</span>)</pre></div><h2 id="b711">The nonlocal Keyword</h2><p id="0157">Now let’s have a look at write-access to variables of the enclosing scope. Initial results show similar behaviour to before, i.e. “modifying” <code>x</code> inside inner does not cause a change in outer:</p><div id="bea4"><pre><span class="hljs-keyword">def</span> <span class="hljs-title function_">outer</span>(): x = <span class="hljs-number">10</span>

<span class="hljs-keyword">def</span> <span class="hljs-title function_">inner</span>():
    x = <span class="hljs-number">20</span>
    <span class="hljs-built_in">print</span>(<span class="hljs-string">f"Value of x in inner: <span class="hljs-subst">{x}</span>"</span>)

inner()
<span class="hljs-built_in">print</span>(<span class="hljs-string">f"Value of x in outer: <span class="hljs-subst">{x}</span>"</span>)

outer()</pre></div><p id="657f">In this case the keyword <code>nonlocal</code> can be used to force this:</p><div id="b2d6"><pre><span class="hljs-keyword">def</span> <span class="hljs-title function_">outer</span>(): x = <span class="hljs-number">10</span>

<span class="hljs-keyword">def</span> <span class="hljs-title function_">inner</span>():
    <span class="hljs-keyword">nonlocal</span> x
    x = <span class="hljs-number">20</span>
    <span class="hljs-built_in">print</span>(<span class="hljs-string">f"Value of x in inner: <span class="hljs-subst">{x}</span>"</span>)

inner()
<span class="hljs-built_in">print</span>(<span class="hljs-string">f"Value of x in outer: <span class="hljs-subst">{x}</span>"</span>)

outer()</pre></div><p id="24cf">Note the same comments about mutable objects hold as for the <code>global</code> keyword — i.e. we don’t need to use <code>nonlocal</code> when working with mutable objects.</p><h2 id="2498">Difference Between Keywords global and nonlocal</h2><p id="8714">Above shown use-cases and usages of global and <code>nonlocal</code> seem fairly similar: in both cases they enable modifying a variable from a larger scope. Nevertheless, they are specific to their respective use-cases, i.e. one cannot use <code>nonlocal</code> to modify a global variable from within a function. Another distinction is that <code>nonlocal</code> needs a previously created variable — while using <code>global</code> from within a function can bind a new variable to the global namespace:</p><div id="cf21"><pre><span class="hljs-keyword">def</span> <span class="hljs-title function_">foo</span>(): <span class="hljs-keyword">global</span> x x = <span class="hljs-number">10</span>

foo() <span class="hljs-built_in">print</span>(<span class="hljs-string">f"Accessing x from the global namespace: <span class="hljs-subst">{x}</span>"</span>)</pre></div><h1 id="b00c">In Plain English 🚀</h1><p id="eb89"><i>Thank you for being a part of the <a href="https://plainenglish.io"><b>In Plain English</b></a> community! Before you go:</i></p><ul><li>Be sure to <b>clap</b> and <b>follow</b> the writer ️👏<b>️️</b></li><li>Follow us: <a href="https://twitter.com/inPlainEngHQ"><b>X</b></a><b> | <a href="https://www.linkedin.com/company/inplainenglish/">LinkedIn</a> | <a href="https://www.youtube.com/channel/UCtipWUghju290NWcn8jhyAw">YouTube</a> | <a href="https://discord.gg/in-plain-english-709094664682340443">Discord</a> | <a href="https://newsletter.plainenglish.io/">Newsletter</a></b></li><li>Visit our other platforms: <a href="https://stackademic.com/"><b>Stackademic</b></a><b> | <a href="https://cofeed.app/">CoFeed</a> | <a href="https://venturemagazine.net/">Venture</a> | <a href="https://blog.cubed.run">Cubed</a></b></li><li>More content at <a href="https://plainenglish.io"><b>PlainEnglish.io</b></a></li></ul></article></body>

Variable Scopes in Python

Understanding the ‘LEGB’ Rule

In Python, there are four different variable scopes: Local, Enclosing, Global, Built-in. This leads to the ‘LEGB’ rule, which defines how Python resolves / looks up names. In this post we will introduce all scopes with examples, and also show how one can ‘interact’ between these — e.g. via the global or nonlocal keyword.

Photo by Roman Synkevych 🇺🇦 on Unsplash

Python, compared to other languages like C++, does not know the concept of declaring a variable. A variable simply is created the moment we first assign a value to it. It is only available in the “region” / “area” it was created in — this is called scope. In the following we will introduce the four available variable scopes: Local, Enclosing, Global, Built-in.

Local Scope

Variables created inside a function belong to the local scope corresponding to that function — and are not available outside:

def foo():
    x = 10
    print(f"Value of x in foo: {x}")

foo()
print(f"Value of x outside: {x}")

In above example, x is a local variable inside foo’s scope — and trying to access it from outside yields an error.

Enclosing Scope

For example in this previous post about closures we have seen inner functions — functions declared inside another, also called nested functions. In this case, the nested function has access to the variables of the outer function, that is, those of the enclosing scope.

def outer():
    x = 10

    def inner():
        y = 20
        print(f"Value of x in inner: {x}")

    inner()
    # print(y) - this would fail

outer()

inner can access x from the enclosing scope, but outer cannot access inner’s local variable y.

Global Scope

The global scope contains all variables defined outside of any function — all functions have access to the contained variables:

x = 10
def foo():
    print(f"Value of x inside foo: {x}")

foo()
print(f"Value of x outside foo: {x}")

Built-in Scope

The built-in scope is the widest scope, and contains all built-in keywords, which you can use anywhere in your code without importing or defining them. A list of Python keywords can be found here.

Modifying Variables of Different Scopes.

Above explanations were probably quite easy to read and understand — however, things get a little bit more complicated, when wanting to modify variables of different scopes. So far, we used them read-only.

Writing Global Variables

Consider the following code:

x = 10
def foo():
    x = 20
    print(f"Value of x inside foo: {x}")

foo()
print(f"Value of x outside foo: {x}")

This prints:

Value of x inside foo: 20
Value of x outside foo: 10

Potentially not what you expected — although x is changed to 20 inside foo, this does not reflect outside. The reason is that variables created inside a function are local by default — i.e. a new variable x with value 20 is created inside foo. Also trying something like x += 10 would raise UnboundLocalError: local variable ‘x’ referenced before assignment — as in this case x is correctly identified as a global variable, but we cannot modify it by default. For this, we can use the global keyword, afterwards causing both prints to be 20:

x = 10

def foo():
    global x
    x = 20
    print(f"Value of x inside foo: {x}")

foo()
print(f"Value of x outside foo: {x}")

Modifying Mutable Objects

To complicate things a little further, things change when working with mutable objects, such as lists. What we discussed above, i.e. the no-write access for global variables from within a function, actually only forbids the direct assignment (x = …). However, as we have read access to the object, we can also call functions using it — and in particular modify the contents!

This code works for example without the global keyword, for this reason:

x = [0, 1]

def foo():
    x.append(2)
    print(f"Value of x inside foo: {x}")

foo()
print(f"Value of x outside foo: {x}")

The nonlocal Keyword

Now let’s have a look at write-access to variables of the enclosing scope. Initial results show similar behaviour to before, i.e. “modifying” x inside inner does not cause a change in outer:

def outer():
    x = 10

    def inner():
        x = 20
        print(f"Value of x in inner: {x}")

    inner()
    print(f"Value of x in outer: {x}")

outer()

In this case the keyword nonlocal can be used to force this:

def outer():
    x = 10

    def inner():
        nonlocal x
        x = 20
        print(f"Value of x in inner: {x}")

    inner()
    print(f"Value of x in outer: {x}")

outer()

Note the same comments about mutable objects hold as for the global keyword — i.e. we don’t need to use nonlocal when working with mutable objects.

Difference Between Keywords global and nonlocal

Above shown use-cases and usages of global and nonlocal seem fairly similar: in both cases they enable modifying a variable from a larger scope. Nevertheless, they are specific to their respective use-cases, i.e. one cannot use nonlocal to modify a global variable from within a function. Another distinction is that nonlocal needs a previously created variable — while using global from within a function can bind a new variable to the global namespace:

def foo():
    global x
    x = 10

foo()
print(f"Accessing x from the global namespace: {x}")

In Plain English 🚀

Thank you for being a part of the In Plain English community! Before you go:

Python
Python Programming
Python Scope
Recommended from ReadMedium