Why isn't the global keyword needed to access a global variable in Python?

Why isn’t the global keyword needed to access a global variable in Python?

From what I understand, Python has a separate namespace for functions, so if I want to modify a global variable inside a function, I would need to use the global keyword.

However, I was able to access a global variable even without using global:

sub = ['0', '0', '0', '0']
def getJoin():
    return '.'.join(sub)

print(getJoin())  # Output: '0.0.0.0'

Why does this work without needing the Python global keyword?

In Python, the global keyword is only required when you want to modify a global variable from within a function. However, if you’re only reading the global variable, you don’t need the global keyword. In your case, the function getJoin() only reads the global sub variable and doesn’t attempt to modify it, so Python allows direct access without the need for global.

sub = ['0', '0', '0', '0']
def getJoin():
    return '.'.join(sub)  # Reading the global variable, no modification

print(getJoin())  # Output: '0.0.0.0'

If you were to assign a value to the sub variable inside the function, then you would need to use global to modify the global variable. Without global, Python will treat sub as a local variable inside the function, and any changes will not affect the global variable.

sub = ['0', '0', '0', '0']
def getJoin():
    sub = ['1', '1', '1', '1']  # Local assignment, won't affect global variable
    return '.'.join(sub)

print(getJoin())  # Output: '1.1.1.1'
print(sub)  # Output: ['0', '0', '0', '0'] (Global variable unchanged)

Python follows LEGB (Local, Enclosing, Global, Built-in) scoping rules. If you access a variable inside a function, Python first looks for the variable in the local scope. If it’s not found, it looks in the enclosing scope, then the global scope.

Since sub exists globally and is not modified locally, Python can access it without the global keyword. The global keyword is only needed when you want to modify the global variable directly from within the function.

sub = ['0', '0', '0', '0']
def getJoin():
    # No global keyword, because we are only reading the variable
    return '.'.join(sub)

print(getJoin())  # Output: '0.0.0.0'