Reputation: 5201
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
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
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
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