Search code examples
pythonfunctionvariables

Variable not available to sub-function


This script defines a variable inside main(), but the variable isn't available to func(), which runs inside main(). Why is that?

#!/usr/bin/env python3
# vars_in_func.py
# Test script for variables within a function.

def func():
  print(greeting)

def main():
  greeting = "Hello world"
  func()

main()

Error:

Traceback (most recent call last):
  File "./vars_in_func.py", line 11, in <module>
    main()
  File "./vars_in_func.py", line 9, in main
    func()
  File "./vars_in_func.py", line 5, in func
    print(greeting)
NameError: name 'greeting' is not defined

If I convert the script to Python2, the error is the same, except it says global name instead of name.

I assume I'm just missing a key concept. I just started learning Python after learning Bash.

Edit: After reading the answers, I realized my mistake: I'm still thinking in terms of Bash, where functions either run in the same shell as the caller (with the same variables), or a subshell of the caller (inherited variables).


Solution

  • There are a lot of answers about python scoping rules, and it really matters here. But as I see your question, your misunderstanding consists in something completely different: a huge difference between defining function and calling it.

    LEGB rule is important but what really matters here is that "Although scopes are determined statically, they are used dynamically". Roughly, function knows where to look for variable (when compiled), but it does not know the variables value (before you call function).

    In your case you simply call one function into the body of another function. When you call function the caller passes control to the callee (roughly, imagine this as a jump in your source code to the beginning of the function's codeblock). So when you call func you jump into func body. This function tries to find names: print and greeting (this process is called name resolution). It looks in local scope, then in global scope (the scope where it was defined, not called) and finally in builtins. It finds only print in builtins. Because it did not find greeting name, an exception NameError is raised. The exception is raised at the point where the error is detected, in your case in the place where main called func. And when an exception is not handled at all, the interpreter terminates execution of the program, or returns to its interactive main loop. In either case, it prints a stack trace, except when the exception is SystemExit.

    One more place to look for information: The Python Language Reference: Execution model

    p.s.: the global scope is always module (file with code) where function was defined. It is very important to understand!!!