5

Simple question about variable scope: Why is it that variables declared in the main function are accessible from external functions? I.e. Why does the following print "yes"?

def run():
    print var

if __name__ == '__main__':
    var = 'yes'
    run()

And is there a way to "turn this off"? In terms of writing good code, it doesn't help to be able to overlook passing variables into functions as arguments, and still have your code run.

Stuart C
  • 165
  • 3
  • 9
  • 2
    That's not a "main function"; it's just an if statement. You can define a function called `main` (or anything else) and only call it inside the `if` if you like. – Ry- Dec 09 '16 at 12:42
  • 3
    The misconception is that there is no main function in your code. The only function there is, is `run()` and `run`can of course see all outer variables (although not change them). – ImportanceOfBeingErnest Dec 09 '16 at 12:43

2 Answers2

6

If-statements don't create new scope in Python. There's no way to "turn this off"; it's a core part of how the language works.

You can use a main function to wrap it in a new scope (this is usually what you want to do; avoid cluttering the namespace) and call it from your main-guard as so:

def run():
    print var

def main():
    var = 'yes'
    run()

if __name__ == '__main__':
    main()
Filip Haglund
  • 13,919
  • 13
  • 64
  • 113
1

Just to help any confusion for future readers, let me just explain what's happening behind the scenes here. In OP's code:

def run():
    print var

if __name__ == '__main__':
    var = 'yes'
    run()

var is declared at the top-level of the file and so var automatically becomes a global variable.* Then run() will notice that var exists in the global scope and it'll simply print it.

This behaviour is often undesirable* so the solution is to avoid having var be a global variable. To do that we need to declare var inside of a function or class. One example:

def run():
    print var  # this line will fail, which is what we want

def main():
    var = 'yes'
    run()

if __name__ == '__main__':
    main()

Since var is declared inside a function, in this case main(), var only exists inside main()'s local scope. run() will notice that var doesn't exist inside its own local scope or in the global scope and it will fail.

*In Python, any variable declared at the top-level (meaning its not declared inside a function or class, it's just out in the open) is automatically considered a global variable. Global variables can be accessed from anywhere. This is typically undesirable. This is why good programmers will usually avoid writing top-level code and just put all their code in a main() function or other functions/classes.

*See why here. Or just google "python why are global variables undesirable".

jaquinocode
  • 634
  • 7
  • 12