Charlie Parker
Charlie Parker

Reputation: 5201

Why don't we need to define global variables before they are actually used in functions in Python?

I was looking at the following code:

def f():
    print(x)

if __name__ == '__main__':
    x = [1,2,3]
    f()

which to my amazement works. I would have expected that NOT to work because I would have expected needing x to be defined BEFORE the function definition of f (otherwise, how does f know what x refers to?). So I expected the following to be the only version that should have worked:

x = [1,2,3]
def f():
    print(x)

if __name__ == '__main__':
    #x = [1,2,3]
    f()

though I am obviously wrong. Why? What part of how Python is supposed to work did I get wrong?


Note as coding practice I'd never use globals. They are dangerous and unclear. I'd personally always pass variables to functions (or something that is more clear and safe like that). This was just out of curiosity.

Upvotes: 2

Views: 334

Answers (3)

stormfield
stormfield

Reputation: 1758

In the first version ie :

def f():
    print(x)

if __name__ == '__main__':
    x = [1,2,3]
    f()

The variable x is in scope thanks to the enclosing scope of if block , since python doesn't have a block scope x is in local scope to the function f()

Where as in the second version:

x = [1,2,3]
def f():
    print(x)

if __name__ == '__main__':
    f()

x is in global scope. Hence inaccessible unless you explicitly include global x in inside the definition of f(), which is NOT a good practice.

Read the following excerpt from the official documentation :

A scope is a textual region of a Python program where a namespace is directly accessible. “Directly accessible” here means that an unqualified reference to a name attempts to find the name in the namespace.

Although scopes are determined statically, they are used dynamically. At any time during execution, there are at least three nested scopes whose namespaces are directly accessible:

  • the innermost scope, which is searched first, contains the local names

  • the scopes of any enclosing functions, which are searched starting with the nearest enclosing scope, contains non-local, but also non-global names

  • the next-to-last scope contains the current module’s global names

  • the outermost scope (searched last) is the namespace containing built-in names

Upvotes: 1

user2357112
user2357112

Reputation: 280181

You do need to define the variable before it's used:

def f():
    print(x)

if __name__ == '__main__':
    x = [1,2,3] # definition
    f()         # use

If you had tried it the other way around:

def f():
    print(x)

if __name__ == '__main__':
    f()         # use
    x = [1,2,3] # definition

it wouldn't have worked.

When you define f, you're not using x. You're just writing code that will eventually use x once called. That code will go look for the x variable when it actually tries to use it, not at function definition time.

Upvotes: 3

josepdecid
josepdecid

Reputation: 1847

Why shouldn't it work? When you're creating the function it's just a code snippet that it isn't executed (kind of lazy evaluation) until it's called. That's the difference between Python and other compiled languages such as C++, which would raise undefined variable x error.

You'll just need the variable x to exist when you call the function f. It will first look at some variable x in the local scope and then in the global scope, so that's why it works anyway, even if x it's been defined after the function!

Upvotes: 4

Related Questions