397

This could be a simple scoping question. The following code in a Python file (module) is confusing me slightly:

if __name__ == '__main__':
    x = 1
    
print x

In other languages I've worked in, this code would throw an exception, as the x variable is local to the if statement and should not exist outside of it. But this code executes, and prints 1. Can anyone explain this behavior? Are all variables created in a module global/available to the entire module?

starball
  • 20,030
  • 7
  • 43
  • 238
froadie
  • 79,995
  • 75
  • 166
  • 235
  • 28
    Another quirk you might not be aware of: if the `if` statement above does not hold true (i.e., `__name__` is *not* `'__main__'`, for example when you import the module instead of executing it top-level), then `x` will never have been bound, and the subsequent `print x` statement will throw a `NameError: name 'x' is not defined`. – Santa May 13 '10 at 20:22
  • See also: https://stackoverflow.com/questions/291978/short-description-of-the-scoping-rules – Karl Knechtel Jul 07 '22 at 09:59

7 Answers7

500

Python variables are scoped to the innermost function, class, or module in which they're assigned. Control blocks like if and while blocks don't count, so a variable assigned inside an if is still scoped to a function, class, or module.

(Implicit functions defined by a generator expression or list/set/dict comprehension do count, as do lambda expressions. You can't stuff an assignment statement into any of those, but lambda parameters and for clause targets are implicit assignment.)

user2357112
  • 260,549
  • 28
  • 431
  • 505
Luke Maurer
  • 7,845
  • 2
  • 24
  • 24
  • 4
    @chandr3sh https://docs.python.org/3/tutorial/classes.html#python-scopes-and-namespaces – Fakher Mokadem Nov 15 '19 at 08:24
  • 6
    Thanks for this answer. I've been coding in python for years now and didn't understand this until now. Knowing this does makes things easier. I always found the way python handle scopes to be of a con sometimes. – AndreGraveler Mar 07 '22 at 03:50
  • The scope created by classes is **temporary** - it only exists as long as the class itself is being created, and then the contents are converted into *attributes of* the class object. It is not possible, for example, to access those names as plain names within the code of methods, even using `nonlocal` in 3.x. They can be found as attributes on `self` (even though that is an instance of the object rather than the class), but that is a special behaviour *of attribute lookup, not* scope resolution. – Karl Knechtel Sep 11 '22 at 05:00
  • In 2.x, comprehensions and generator expressions don't create an "implicit function", or at least, don't create a new scope for the code; and e.g. an iteration variable can "leak" out of a list comprehension just as it would from a `for` loop. In 3.8 and above, the "walrus" `:=` operator **can** be used in a comprehension to assign to a variable in the outer scope: e.g. after `x = 0`, `[_ for x in [1]]` does not modify the outer `x`, but `[x:=1 for _ in range(1)]` **does**. – Karl Knechtel Sep 11 '22 at 05:05
163

Yes, they're in the same "local scope", and actually code like this is common in Python:

if condition:
  x = 'something'
else:
  x = 'something else'

use(x)

Note that x isn't declared or initialized before the condition, like it would be in C or Java, for example.

In other words, Python does not have block-level scopes. Be careful, though, with examples such as

if False:
    x = 3
print(x)

which would clearly raise a NameError exception.

nbro
  • 15,395
  • 32
  • 113
  • 196
Eli Bendersky
  • 263,248
  • 89
  • 350
  • 412
  • 4
    I fell in the `if False:` trap. – steoiatsl Nov 23 '21 at 07:05
  • 1
    Do you know: Did this change in python3.10? After updating I get some errors in connection with scope. For example: `if condition: i = 2 else: i = 0 for var in array: i += 1` -> This results in TypeError: unsupported operand type(s) for +=: 'NoneType' and 'int' – chakmear Dec 08 '22 at 09:55
48

Scope in python follows this order:

  • Search the local scope

  • Search the scope of any enclosing functions

  • Search the global scope

  • Search the built-ins

(source)

Notice that if and other looping/branching constructs are not listed - only classes, functions, and modules provide scope in Python, so anything declared in an if block has the same scope as anything decleared outside the block. Variables aren't checked at compile time, which is why other languages throw an exception. In python, so long as the variable exists at the time you require it, no exception will be thrown.

Daniel G
  • 67,224
  • 7
  • 42
  • 42
16

Unlike languages such as C, a Python variable is in scope for the whole of the function (or class, or module) where it appears, not just in the innermost "block". It is as though you declared int x at the top of the function (or class, or module), except that in Python you don't have to declare variables.

Note that the existence of the variable x is checked only at runtime -- that is, when you get to the print x statement. If __name__ didn't equal "__main__" then you would get an exception: NameError: name 'x' is not defined.

Paul Stephenson
  • 67,682
  • 9
  • 49
  • 51
  • Classes do not create a scope; a "local" variable in a class is simply added to the class's dict upon creation. – chepner Aug 20 '15 at 18:14
15

As Eli said, Python doesn't require variable declaration. In C you would say:

int x;
if(something)
    x = 1;
else
    x = 2;

but in Python declaration is implicit, so when you assign to x it is automatically declared. It's because Python is dynamically typed - it wouldn't work in a statically typed language, because depending on the path used, a variable might be used without being declared. This would be caught at compile time in a statically typed language, but with a dynamically typed language it's allowed.

The only reason that a statically typed language is limited to having to declare variables outside of if statements in because of this problem. Embrace the dynamic!

Skilldrick
  • 69,215
  • 34
  • 177
  • 229
6

Yes. It is also true for for scope. But not functions of course.

In your example: if the condition in the if statement is false, x will not be defined though.

Olivier Verdier
  • 46,998
  • 29
  • 98
  • 90
3

you're executing this code from command line therefore if conditions is true and x is set. Compare:

>>> if False:
    y = 42


>>> y
Traceback (most recent call last):
  File "<pyshell#6>", line 1, in <module>
    y
NameError: name 'y' is not defined
SilentGhost
  • 307,395
  • 66
  • 306
  • 293