14.5. Function Scope

  • Values defined in function does not leak out

  • Functions has access to global values

  • Shadowing is when you define variable with name identical to the one from outer scope

  • After function return, the original value of a shadowed variable is restored

  • global keyword allows modification of global variable

  • Using global keyword is considered as a bad practice

In Python, a function scope refers to the area of a program where a variable is accessible. A variable's scope is determined by where it is defined in the program.

When a variable is defined inside a function, it has local scope, which means that it can only be accessed within that function. Local variables are destroyed when the function returns.

Here's an example of using local variables in Python:

>>> def login():
...     authenticated = True
...     print(authenticated)
>>>
>>> login()
True
>>>
>>> print(authenticated)
Traceback (most recent call last):
NameError: name 'authenticated' is not defined

In this example, the authenticated variable is defined inside the login() function. It has local scope and can only be accessed within the function. When the function is called, it prints the value of authenticated. When the function returns, the authenticated variable is destroyed.

If we try to access the authenticated variable outside the function, we get a NameError because the variable is not defined in the global scope.

Variables defined outside of any function have global scope, which means that they can be accessed from anywhere in the program. Global variables are not destroyed when a function returns.

Here's an example of using global variables in Python:

>>> authenticated = True
>>>
>>> def login():
...     print(authenticated)
>>>
>>> login()
True
>>>
>>> authenticated
True

In this example, the authenticated variable is defined outside of any function and has global scope. It can be accessed from within the login() function and from outside the function. When the function is called, it prints the value of authenticated. When the program ends, the authenticated variable is not destroyed because it has global scope.

Using function scope helps to keep variables organized and prevent naming conflicts between different parts of a program.

14.5.1. Globals

  • globals() returns a dictionary containing the global variables

  • Each variable in the dictionary is a key-value pair where the key is the variable name and the value is the variable value

>>> 'authenticated' in globals()
False
>>>
>>> authenticated = True
>>>
>>> 'authenticated' in globals()
True

14.5.2. Locals

  • locals() returns a dictionary containing the variables defined in the current scope

  • locals() is useful for debugging and introspection

>>> def login(username, password=None):
...     authenticated = False
...     print(locals())
>>>
>>>
>>> login('mwatney')
{'username': 'mwatney', 'password': None, 'authenticated': False}

14.5.3. Local Scope

  • Values defined in function does not leak out

>>> authenticated
Traceback (most recent call last):
NameError: name 'authenticated' is not defined
>>>
>>> def login():
...     authenticated = True
...     print(authenticated)
>>>
>>> authenticated
Traceback (most recent call last):
NameError: name 'authenticated' is not defined
>>>
>>> login()
True
>>>
>>> authenticated
Traceback (most recent call last):
NameError: name 'authenticated' is not defined

14.5.4. Global Scope

  • Functions has access to global values

>>> authenticated = False
>>>
>>> def login():
...     print(authenticated)
>>>
>>> authenticated
False
>>>
>>> login()
False
>>>
>>> authenticated
False

14.5.5. Shadowing

  • When variable in function has the same name as in outer scope

  • Shadowing in a function is valid only in a function

  • Shadowed variable will be deleted upon function return

  • After function return, the original value of a shadowed variable is restored

>>> authenticated = False
>>>
>>> def login():
...     authenticated = True
...     print(authenticated)
>>>
>>> authenticated
False
>>>
>>> login()
True
>>>
>>> authenticated
False

14.5.6. Assignments

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% About
# - Name: Function Scope Locals
# - Difficulty: easy
# - Lines: 1
# - Minutes: 2

# %% English
# 1. Modify function `run`
# 2. Calling function should print value of local variables `a` and `b`
# 3. Run doctests - all must succeed

# %% Polish
# 1. Zmodyfikuj funkcję `run`
# 2. Wywołanie funkcji powinno wypisać wartość zmiennych lokalnych `a` i `b`
# 3. Uruchom doctesty - wszystkie muszą się powieść

# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'

>>> from inspect import isfunction

>>> assert run is not Ellipsis, \
'Write solution inside `run` function'
>>> assert isfunction(run), \
'Object `run` must be a function'

>>> run()
a=1, b=2
"""

# Calling function should print value of local variables `a` and `b`
# type: Callable[[], None]
def run():
    a = 1
    b = 2


# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% About
# - Name: Function Scope Globals
# - Difficulty: easy
# - Lines: 1
# - Minutes: 2

# %% English
# 1. Modify function `run`
# 2. Calling function should print value of global variables `a` and `b`
# 3. Run doctests - all must succeed

# %% Polish
# 1. Zmodyfikuj funkcję `run`
# 2. Wywołanie funkcji powinno wypisać wartość zmiennych globalnych `a` i `b`
# 3. Uruchom doctesty - wszystkie muszą się powieść

# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'

>>> from inspect import isfunction

>>> assert run is not Ellipsis, \
'Write solution inside `run` function'
>>> assert isfunction(run), \
'Object `run` must be a function'

>>> run()
a=1, b=2
"""

a = 1
b = 2

# Calling function should print value of global variables `a` and `b`
# type: Callable[[], None]
def run():
    ...


# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% About
# - Name: Function Scope Locals
# - Difficulty: easy
# - Lines: 1
# - Minutes: 2

# %% English
# 1. Modify function `run` with local variables `a=1` and `b=2`
# 2. Return `dict` with variable names and their values,
#    example: {'a': 1, 'b': 2}
# 3. Use `locals()` function
# 6. Run doctests - all must succeed

# %% Polish
# 1. Zmodyfikuj funkcję `run` z lokalnymi zmiennymi `a=1` i `b=2`
# 2. Zwróć `dict` z nazwami zmiennych i ich wartościami,
#    przykład: {'a': 1, 'b': 2}
# 3. Użyj funkcji `locals()`
# 4. Uruchom doctesty - wszystkie muszą się powieść

# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'

>>> from inspect import isfunction

>>> assert run is not Ellipsis, \
'Write solution inside `run` function'
>>> assert isfunction(run), \
'Object `run` must be a function'

>>> run()
{'a': 1, 'b': 2}
"""

# Return `dict` with variable names and its values, example: {'a': 1, 'b': 2}
# Use `locals()` function
# type: Callable[[], dict[str,int]]
def run():
    a = 1
    b = 2
    return ...