Skip to main content
use clearer grammar and add a link to an example Q&A
Source Link
Karl Knechtel
  • 61.4k
  • 14
  • 132
  • 193
  • It does not matter if the global variable is a builtin function etc., rather than an explicitly created global:
    def x(): int = int('1') # `int` is local! 
    (Of course, it is a bad idea to shadow builtin names like this anyway, and global cannot help - just like using the same code outside of a function will still cause problems.)
  • It does not matter if the code could never be reached:
    y = 1 def x(): return y # local! if False: y = 0 
  • It does not matter if the assignment would be optimized into an in-place modification (e.g. extending a list) - conceptually, the value is still assigned, and this is reflected in the bytecode in the reference implementation as a useless reassignment of the name to the same object:
    y = [] def x(): y += [1] # local, even though it would modify `y` in-place with `global` 
  • However, it does matter if we do an indexed/slice assignment instead. (This is transformed into a different opcode at compile time, which will in turn call __setitem__.)
    y = [0] def x(): print(y) # global now! No error occurs. y[0] = 1 
  • There are other forms of assignment, e.g. for loops and imports:
    import sys y = 1 def x(): return y # local! for y in []: pass def z(): print(sys.path) # `sys` is local! import sys 
  • Another common way to cause problems with import is trying to reuse the module name as a local variable, like so:
    import random def x(): random = random.choice(['heads', 'tails']) 
    Again, import is assignment, so there is a global variable random. But this global variable is not special; it can just as easily be shadowed by the local random.
  • Deletion is also changing the name bindingDeleting something also changes the name binding, e.g.:
    y = 1 def x(): return y # local! del y 
  • It does not matter if the global variable is a builtin function etc., rather than an explicitly created global:
    def x(): int = int('1') # `int` is local! 
    (Of course, it is a bad idea to shadow builtin names like this anyway, and global cannot help - just like using the same code outside of a function will still cause problems.)
  • It does not matter if the code could never be reached:
    y = 1 def x(): return y # local! if False: y = 0 
  • It does not matter if the assignment would be optimized into an in-place modification (e.g. extending a list) - conceptually, the value is still assigned, and this is reflected in the bytecode in the reference implementation as a useless reassignment of the name to the same object:
    y = [] def x(): y += [1] # local, even though it would modify `y` in-place with `global` 
  • However, it does matter if we do an indexed/slice assignment instead. (This is transformed into a different opcode at compile time, which will in turn call __setitem__.)
    y = [0] def x(): print(y) # global now! No error occurs. y[0] = 1 
  • There are other forms of assignment, e.g. for loops and imports:
    import sys y = 1 def x(): return y # local! for y in []: pass def z(): print(sys.path) # `sys` is local! import sys 
  • Another common way to cause problems with import is trying to reuse the module name as a local variable, like so:
    import random def x(): random = random.choice(['heads', 'tails']) 
    Again, import is assignment, so there is a global variable random. But this global variable is not special; it can just as easily be shadowed by the local random.
  • Deletion is also changing the name binding, e.g.:
    y = 1 def x(): return y # local! del y 
  • It does not matter if the global variable is a builtin function etc., rather than an explicitly created global:
    def x(): int = int('1') # `int` is local! 
    (Of course, it is a bad idea to shadow builtin names like this anyway, and global cannot help - just like using the same code outside of a function will still cause problems.)
  • It does not matter if the code could never be reached:
    y = 1 def x(): return y # local! if False: y = 0 
  • It does not matter if the assignment would be optimized into an in-place modification (e.g. extending a list) - conceptually, the value is still assigned, and this is reflected in the bytecode in the reference implementation as a useless reassignment of the name to the same object:
    y = [] def x(): y += [1] # local, even though it would modify `y` in-place with `global` 
  • However, it does matter if we do an indexed/slice assignment instead. (This is transformed into a different opcode at compile time, which will in turn call __setitem__.)
    y = [0] def x(): print(y) # global now! No error occurs. y[0] = 1 
  • There are other forms of assignment, e.g. for loops and imports:
    import sys y = 1 def x(): return y # local! for y in []: pass def z(): print(sys.path) # `sys` is local! import sys 
  • Another common way to cause problems with import is trying to reuse the module name as a local variable, like so:
    import random def x(): random = random.choice(['heads', 'tails']) 
    Again, import is assignment, so there is a global variable random. But this global variable is not special; it can just as easily be shadowed by the local random.
  • Deleting something also changes the name binding, e.g.:
    y = 1 def x(): return y # local! del y 
better explanation of the need for compilation (`eval` and `exec` don't create code objects); fix a link
Source Link
Karl Knechtel
  • 61.4k
  • 14
  • 132
  • 193

Contrary to popular belief, Python is not an "interpreted" language in any meaningful sense. (Those are vanishingly rare now.) The reference implementation of Python compiles Python code in much the same way as Java or C#: it is translated into opcodes ("bytecode") for a virtual machine, which is then emulated. Other implementations must also compile the code; otherwise, eval andcode exec could not properly return an object, and- so that SyntaxErrors could notcan be detected without actually running the code, and in order to implement the "compilation services" portion of the standard library.

  • It does not matter if the global variable is a builtin function etc., rather than an explicitly created global:
    def x(): int = int('1') # `int` is local! 
    (Of course, it is a bad idea to shadow builtin names like this anyway, and global cannot help (just- just like using the same code outside of a function will still cause problems). See https://stackoverflow.com/questions/6039605.will still cause problems.)
  • It does not matter if the code could never be reached:
    y = 1 def x(): return y # local! if False: y = 0 
  • It does not matter if the assignment would be optimized into an in-place modification (e.g. extending a list) - conceptually, the value is still assigned, and this is reflected in the bytecode in the reference implementation as a useless reassignment of the name to the same object:
    y = [] def x(): y += [1] # local, even though it would modify `y` in-place with `global` 
  • However, it does matter if we do an indexed/slice assignment instead. (This is transformed into a different opcode at compile time, which will in turn call __setitem__.)
    y = [0] def x(): print(y) # global now! No error occurs. y[0] = 1 
  • There are other forms of assignment, e.g. for loops and imports:
    import sys y = 1 def x(): return y # local! for y in []: pass def z(): print(sys.path) # `sys` is local! import sys 
  • Another common way to cause problems with import is trying to reuse the module name as a local variable, like so:
    import random def x(): random = random.choice(['heads', 'tails']) 
    Again, import is assignment, so there is a global variable random. But this global variable is not special; it can just as easily be shadowed by the local random.
  • Deletion is also changing the name binding, e.g.:
    y = 1 def x(): return y # local! del y 

Contrary to popular belief, Python is not an "interpreted" language in any meaningful sense. (Those are vanishingly rare now.) The reference implementation of Python compiles Python code in much the same way as Java or C#: it is translated into opcodes ("bytecode") for a virtual machine, which is then emulated. Other implementations must also compile the code; otherwise, eval and exec could not properly return an object, and SyntaxErrors could not be detected without actually running the code.

  • It does not matter if the global variable is a builtin function etc., rather than an explicitly created global:
    def x(): int = int('1') # `int` is local! 
    (Of course, it is a bad idea to shadow builtin names like this anyway, and global cannot help (just like using the same code outside of a function will still cause problems). See https://stackoverflow.com/questions/6039605.)
  • It does not matter if the code could never be reached:
    y = 1 def x(): return y # local! if False: y = 0 
  • It does not matter if the assignment would be optimized into an in-place modification (e.g. extending a list) - conceptually, the value is still assigned, and this is reflected in the bytecode in the reference implementation as a useless reassignment of the name to the same object:
    y = [] def x(): y += [1] # local, even though it would modify `y` in-place with `global` 
  • However, it does matter if we do an indexed/slice assignment instead. (This is transformed into a different opcode at compile time, which will in turn call __setitem__.)
    y = [0] def x(): print(y) # global now! No error occurs. y[0] = 1 
  • There are other forms of assignment, e.g. for loops and imports:
    import sys y = 1 def x(): return y # local! for y in []: pass def z(): print(sys.path) # `sys` is local! import sys 
  • Another common way to cause problems with import is trying to reuse the module name as a local variable, like so:
    import random def x(): random = random.choice(['heads', 'tails']) 
    Again, import is assignment, so there is a global variable random. But this global variable is not special; it can just as easily be shadowed by the local random.
  • Deletion is also changing the name binding, e.g.:
    y = 1 def x(): return y # local! del y 

Contrary to popular belief, Python is not an "interpreted" language in any meaningful sense. (Those are vanishingly rare now.) The reference implementation of Python compiles Python code in much the same way as Java or C#: it is translated into opcodes ("bytecode") for a virtual machine, which is then emulated. Other implementations must also compile the code - so that SyntaxErrors can be detected without actually running the code, and in order to implement the "compilation services" portion of the standard library.

  • It does not matter if the global variable is a builtin function etc., rather than an explicitly created global:
    def x(): int = int('1') # `int` is local! 
    (Of course, it is a bad idea to shadow builtin names like this anyway, and global cannot help - just like using the same code outside of a function will still cause problems.)
  • It does not matter if the code could never be reached:
    y = 1 def x(): return y # local! if False: y = 0 
  • It does not matter if the assignment would be optimized into an in-place modification (e.g. extending a list) - conceptually, the value is still assigned, and this is reflected in the bytecode in the reference implementation as a useless reassignment of the name to the same object:
    y = [] def x(): y += [1] # local, even though it would modify `y` in-place with `global` 
  • However, it does matter if we do an indexed/slice assignment instead. (This is transformed into a different opcode at compile time, which will in turn call __setitem__.)
    y = [0] def x(): print(y) # global now! No error occurs. y[0] = 1 
  • There are other forms of assignment, e.g. for loops and imports:
    import sys y = 1 def x(): return y # local! for y in []: pass def z(): print(sys.path) # `sys` is local! import sys 
  • Another common way to cause problems with import is trying to reuse the module name as a local variable, like so:
    import random def x(): random = random.choice(['heads', 'tails']) 
    Again, import is assignment, so there is a global variable random. But this global variable is not special; it can just as easily be shadowed by the local random.
  • Deletion is also changing the name binding, e.g.:
    y = 1 def x(): return y # local! del y 
give an explicit example of another common beginner gotcha
Source Link
Karl Knechtel
  • 61.4k
  • 14
  • 132
  • 193
  • It does not matter if the global variable is a builtin function etc., rather than an explicitly created global:
    def x(): int = int('1') # `int` is local! 
    (Of course, it is a bad idea to shadow builtin names like this anyway, and global cannot help (just like using the same code outside of a function will still cause problems). See https://stackoverflow.com/questions/6039605.)
  • It does not matter if the code could never be reached:
    y = 1 def x(): return y # local! if False: y = 0 
  • It does not matter if the assignment would be optimized into an in-place modification (e.g. extending a list) - conceptually, the value is still assigned, and this is reflected in the bytecode in the reference implementation as a useless reassignment of the name to the same object:
    y = [] def x(): y += [1] # local, even though it would modify `y` in-place with `global` 
  • However, it does matter if we do an indexed/slice assignment instead. (This is transformed into a different opcode at compile time, which will in turn call __setitem__.)
    y = [0] def x(): print(y) # global now! No error occurs. y[0] = 1 
  • There are other forms of assignment, e.g. for loops and imports:
    import sys y = 1 def x(): return y # local! for y in []: pass def z(): print(sys.path) # `sys` is local! import sys 
  • Another common way to cause problems with import is trying to reuse the module name as a local variable, like so:
    import random def x(): random = random.choice(['heads', 'tails']) 
    Again, import is assignment, so there is a global variable random. But this global variable is not special; it can just as easily be shadowed by the local random.
  • Deletion is also changing the name binding, e.g.:
    y = 1 def x(): return y # local! del y 
  • It does not matter if the global variable is a builtin function etc., rather than an explicitly created global:
    def x(): int = int('1') # `int` is local! 
    (Of course, it is a bad idea to shadow builtin names like this anyway, and global cannot help (just like using the same code outside of a function will still cause problems). See https://stackoverflow.com/questions/6039605.)
  • It does not matter if the code could never be reached:
    y = 1 def x(): return y # local! if False: y = 0 
  • It does not matter if the assignment would be optimized into an in-place modification (e.g. extending a list) - conceptually, the value is still assigned, and this is reflected in the bytecode in the reference implementation as a useless reassignment of the name to the same object:
    y = [] def x(): y += [1] # local, even though it would modify `y` in-place with `global` 
  • However, it does matter if we do an indexed/slice assignment instead. (This is transformed into a different opcode at compile time, which will in turn call __setitem__.)
    y = [0] def x(): print(y) # global now! No error occurs. y[0] = 1 
  • There are other forms of assignment, e.g. for loops and imports:
    import sys y = 1 def x(): return y # local! for y in []: pass def z(): print(sys.path) # `sys` is local! import sys 
  • Deletion is also changing the name binding, e.g.:
    y = 1 def x(): return y # local! del y 
  • It does not matter if the global variable is a builtin function etc., rather than an explicitly created global:
    def x(): int = int('1') # `int` is local! 
    (Of course, it is a bad idea to shadow builtin names like this anyway, and global cannot help (just like using the same code outside of a function will still cause problems). See https://stackoverflow.com/questions/6039605.)
  • It does not matter if the code could never be reached:
    y = 1 def x(): return y # local! if False: y = 0 
  • It does not matter if the assignment would be optimized into an in-place modification (e.g. extending a list) - conceptually, the value is still assigned, and this is reflected in the bytecode in the reference implementation as a useless reassignment of the name to the same object:
    y = [] def x(): y += [1] # local, even though it would modify `y` in-place with `global` 
  • However, it does matter if we do an indexed/slice assignment instead. (This is transformed into a different opcode at compile time, which will in turn call __setitem__.)
    y = [0] def x(): print(y) # global now! No error occurs. y[0] = 1 
  • There are other forms of assignment, e.g. for loops and imports:
    import sys y = 1 def x(): return y # local! for y in []: pass def z(): print(sys.path) # `sys` is local! import sys 
  • Another common way to cause problems with import is trying to reuse the module name as a local variable, like so:
    import random def x(): random = random.choice(['heads', 'tails']) 
    Again, import is assignment, so there is a global variable random. But this global variable is not special; it can just as easily be shadowed by the local random.
  • Deletion is also changing the name binding, e.g.:
    y = 1 def x(): return y # local! del y 
added 464 characters in body
Source Link
Karl Knechtel
  • 61.4k
  • 14
  • 132
  • 193
Loading
`import` is another common "hidden" assignment - show an example explicitly.
Source Link
Karl Knechtel
  • 61.4k
  • 14
  • 132
  • 193
Loading
add reference link to the documentation's "programming FAQ"
Source Link
Karl Knechtel
  • 61.4k
  • 14
  • 132
  • 193
Loading
add summary section and section headings; try to clarify a few points; expand remarks about builtins and move them to the end
Source Link
Karl Knechtel
  • 61.4k
  • 14
  • 132
  • 193
Loading
while canonicalizing duplicate links, I realized that `del` also causes this problem.
Source Link
Karl Knechtel
  • 61.4k
  • 14
  • 132
  • 193
Loading
Source Link
Karl Knechtel
  • 61.4k
  • 14
  • 132
  • 193
Loading