Home > Blockchain >  Python syntax for creating and changing global variables
Python syntax for creating and changing global variables

Time:12-18

Very basic Python question but I want to make sure I'm using the global keyword properly after a couple of false starts.

  1. Creating a variable that needs to be global inside a function:
def my_function():
    global x # creates a global variable
    x = 1
    
my_function()
  1. Changing the value of a global variable that already exists outside of the function that is changing it:
x = 1 # creates a global variable

def my_function():
    global x
    x = 2
    
my_function()

That right?

Seems like a lot of people aren't big fans of global so if there is a better way to handle reading from and writing to multiple global variables from within different functions I'd love to hear it. Thanks!

CodePudding user response:

Yes, that's right and if you add print(x) you will see that it will print 2.

CodePudding user response:

I think you got things the wrong way around: it's not that people aren't big fans of the global keyword and want you to use a different way to re-assign global variables. It's that mutable global state is a code smell in itself.

A "code smell" refers to how expert programmers consider certain code practices to "smell". Much like real world smells, they are not necessarily bad in and of themselves, but they point to possible problems: a real world smell might tell you that food has gone bad or there might be a gas leak. A code smell might tell you the code is going to become an unmaintainable mess if you're not careful, or that the probability of there being bugs you're not seeing is higher than normal.

Mutating global variables means that if you have two functions foo() and bar(), then calling them in a specific order may break things. Example:

X = 0
DATA = 'ok'

def foo():
    global DATA
    if X == 0:
        DATA = 'bad'

def bar():
    global X
    if DATA == 'ok':
        X = 1

Even worse, it may be the case that it depends on whether or not you call spam() in a completely different part of your program! For a couple of functions and global variables, this is usually something you can mentally keep track of, but as your program grows, the opportunities for weird 5D quantum bugs increases exponentially.

The solution is to make data dependencies explicit.

We can do that by, among other things, passing values as arguments and returning values from functions, rather than relying on global variables.

In your example, my_function() could return 2. In my example, instead foo() and bar() both depending and modifying a global variable, they could take a value and return another one. For example:

def foo(x: int) -> str:
    if x == 0:
        return 'bad'
    return 'ok'

def bar(data: str) -> int:
    if data == 'ok':
        return 1
    return 0

Now it's very clear that ordering is important when you call foo() or bar()!

The difference between

foo()
bar()

and

bar()
foo()

... depends on you knowing how foo and bar are implemented.

That

data = foo()
bar(data)

and

x = bar()
foo(x)

don't mean the same thing is obvious from the code itself.

Even better, if you know foo and bar don't depend on mutable global state, you know that the result can't depend on a call to spam() that may or may not happen in a completely different module.

CodePudding user response:

You are mostly correct. However, the global keyword does not create a variable. It simply marks the name as belonging to the global scope, rather than the local scope. For example, the following

def foo():
    global x

foo()

does not create a global variable named x, because there is never an assignment to the name x. Your first example, more precisely commented, would look like

def my_function():
    global x
    x = 1   # creates a global variable if it doesn't already exist
    
my_function()

Global variables are frowned upon because it makes it harder to know who might change a variable, and when or where that change might occur. The alternative is for my_function to receive an argument and/or return a value, and let the caller decide what argument to provide and what to do with the return value. For example,

x = 1  # Global variable

def my_function(y):
    return y   1

x = my_function(x)
assert x == 2

This is not to say you will never use global variables, but you should consider whether it makes sense to use a global instead of passing arguments to and receiving values from a function instead.

  • Related