4

Using and Creating Global Variables in Your Python Functions

 1 year ago
source link: https://realpython.com/python-use-global-variable-in-function/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Using Global Variables in Python Functions

Global variables are those that you can access and modify from anywhere in your code. In Python, you’ll typically define global variables at the module level. So, the containing module is their scope.

Note: You can also define global variables inside functions, as you’ll learn in the section Creating Global Variables Inside a Function.

Once you’ve defined a global variable, you can use it from within the module itself or from within other modules in your code. You can also use global variables in your functions. However, those cases can get a bit confusing because of differences between accessing and modifying global variables in functions.

To understand these differences, consider that Python can look for variables in four different scopes:

  • The local, or function-level, scope, which exists inside functions
  • The enclosing, or non-local, scope, which appears in nested functions
  • The global scope, which exists at the module level
  • The built-in scope, which is a special scope for Python’s built-in names

To illustrate, say that you’re inside an inner function. In that case, Python can look for names in all four scopes.

When you access a variable in that inner function, Python first looks inside that function. If the variable doesn’t exist there, then Python continues with the enclosing scope of the outer function. If the variable isn’t defined there either, then Python moves to the global and built-in scopes in that order. If Python finds the variable, then you get the value back. Otherwise, you get a NameError:

>>> # Global scope

>>> def outer_func():
...     # Non-local scope
...     def inner_func():
...         # Local scope
...         print(some_variable)
...     inner_func()
...

>>> outer_func()
Traceback (most recent call last):
    ...
NameError: name 'some_variable' is not defined

>>> some_variable = "Hello from global scope!"
>>> outer_func()
Hello from global scope!

When you launch an interactive session, it starts off at the module level of global scope. In this example, you have outer_func(), which defines inner_func() as a nested function. From the perspective of this nested function, its own code block represents the local scope, while the outer_func() code block before the call to inner_func() represents the non-local scope.

If you call outer_func() without defining some_variable in either of your current scopes, then you get a NameError exception because the name isn’t defined.

If you define some_variable in the global scope and then call outer_func(), then you get Hello! on your screen. Internally, Python has searched the local, non-local, and global scopes to find some_variable and print its content. Note that you can define this variable in any of the three scopes, and Python will find it.

This search mechanism makes it possible to use global variables from inside functions. However, while taking advantage of this feature, you can face a few issues. For example, accessing a variable works, but directly modifying a variable doesn’t work:

>>> number = 42

>>> def access_number():
...     return number
...

>>> access_number()
42

>>> def modify_number():
...     number = 7
...

>>> modify_number()
>>> number
42

The access_number() function works fine. It looks for number and finds it in the global scope. In contrast, modify_number() doesn’t work as expected. Why doesn’t this function update the value of your global variable, number? The problem is the scope of the variable. You can’t directly modify a variable from a high-level scope like global in a lower-level scope like local.

Internally, Python assumes that any name directly assigned within a function is local to that function. Therefore, the local name, number, shadows its global sibling.

In this sense, global variables behave as read-only names. You can access their values, but you can’t modify them.

Note: The discussion about modifying global variables inside functions revolves around assignment operations rather than in-place mutations of mutable objects. You’ll learn about the effects of mutability on global variables in the section Understanding How Mutability Affects Global Variables.

Getting an UnboundLocalError exception is another common issue when you try to modify a global variable inside a function. Consider the following demonstrative function that attempts to use some global variables:

>>> a = 10
>>> b = 20
>>> c = 30

>>> def print_globals():
...     print(a, b, c)
...     c = 100
...     print(c)
...

Inside print_globals(), you first print the global variables a, b, and c. Then you update the value of c directly. Finally, you print the updated version of c. You may be expecting the following output:

>>> # Expected output
>>> print_globals()
10 20 30
100

However, this output never appears on your screen. Instead, you get an error that might surprise you:

>>> print_globals()
Traceback (most recent call last):
    ...
UnboundLocalError: cannot access local variable 'c'
    where it is not associated with a value

The problem is that the assignment c = 100 creates a new local variable that overrides the original global variable, c. So, you have a name conflict. The exception comes from the first call to print() because, at that time, the local version of c isn’t defined yet. So, you get the UnboundLocalError.

In practice, this issue most often occurs in augmented assignment operations with global variables:

>>> counter = 0

>>> def increment():
...     counter += 1
...

>>> increment()
Traceback (most recent call last):
    ...
UnboundLocalError: cannot access local variable 'counter'
    where it is not associated with a value

In Python, if your function simply references a variable from the global scope, then the function assumes that the variable is global. If you assign the variable’s name anywhere within the function’s body, then you define a new local variable with the same name as your original global.

Inside a function, you can’t access a global variable directly if you’ve defined local variables with the same name anywhere in the function.

If you want to modify a global variable inside a function, then you need to explicitly tell Python to use the global variable rather than creating a new local one. To do this, you can use one of the following:

  1. The global keyword
  2. The built-in globals() function

In the following sections, you’ll learn how to use both tools in your code to change global variables from inside your functions.

The global Keyword

You’ve already learned that accessing global variables directly from inside a function is completely possible unless you have local variables with the same name in the containing function. Apart from that, what if you also need to change the variable’s value? In that case, you can use the global keyword to declare that you want to refer to the global variable.

The general syntax to write a global statement is as follows:

global variable_0, variable_1, ..., variable_n

Note that the first variable is required, while the rest of the variables are optional. To illustrate how you can use this statement, get back to the counter and increment() example. You can fix the code by doing something like the following:

>>> counter = 0

>>> def increment():
...     global counter
...     counter += 1
...

>>> increment()
>>> counter
1
>>> increment()
>>> counter
2

In this new version of increment(), you use the global keyword to declare that you want the function to update the global variable, counter. With this statement, you’re now able to modify the value of counter inside your function, as you can see above.

Note: Python has a nonlocal keyword that works similarly to global. It allows you to use non-local variables from nested functions. Non-local variables are those that you define in a function that holds nested functions. These variables will be non-local to the inner or nested functions.

It’s important to note that you have to do your global declarations before you use the target variable. Otherwise, you’ll get a SyntaxError:

>>> counter = 0

>>> def increment():
...     counter += 1
...     global counter
...
SyntaxError: name 'counter' is assigned to before global declaration

In this example, you try to increment counter without declaring it as global inside increment(). Therefore, you get a SyntaxError.

The global statement tells the Python interpreter when you find the name counter in this function, it refers to the global variable, so don’t create a local one.

In summary, you only need to use the global keyword if you want to reassign the global variable within a function. If you just need to read or access the value of the global variable from within your function, then you don’t need the global keyword.

Even though the goal of the global keyword is to deal with global variables in functions, this keyword isn’t the only tool that you can use for this purpose. You can also use the built-in globals() function.

The globals() Function

The built-in globals() function allows you to access the global scope’s name table, which is a writable dictionary containing your current global names and their corresponding values. You can use this function to either access or modify the value of a global variable from within your functions.

For example, this function comes in handy when you have local variables with the same name as your target global variables, and you still need to use the global variable inside the function:

>>> a = 10
>>> b = 20
>>> c = 30

>>> def print_globals():
...     print(a, b, globals()["c"])
...     c = 100
...     print(c)
...

>>> print_globals()
10 20 30
100

>>> c
30

In this new implementation of print_globals(), c refers to the local version of the variable, while globals()["c"] refers to the global version.

Because globals() returns a dictionary, you can access its keys as you’d access the keys of a regular dictionary. Note that you need to use the variable’s name as a string to access the corresponding key in globals().

The dictionary of names that globals() returns is mutable, which means that you can change the value of existing global variables by taking advantage of this dictionary. In the final example, you can see how the global variable, c, still holds the same value.

Here’s another version of increment(). It’s a bit harder to read, but it works:

>>> counter = 0

>>> def increment():
...     globals()["counter"] += 1
...

>>> increment()
>>> counter
1
>>> increment()
>>> counter
2

In this example, you’ve implemented increment() using globals() instead of the global keyword. Both implementations work the same, which you can confirm from the content of counter after consecutive calls to the function.

Note that using globals() to access and update global variables can make your code difficult to read and understand, especially for large programs. It’s generally better to use the global keyword unless you have local variables with the same name as your target globals.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK