6

Why does this function output 0 1?

Why is a class in a function behaving like a function? Why didn't I have to call A like a function?

How does the assignment statement after print() affect the values of x and y? When I assign value to x, x becomes 0 and if I assign a value to y, y becomes 0.

x = 0
y = 0

def f():
  x = 1
  y = 1
  class A:
    print(x,y)
    x = 99

f()
user202729
  • 3,358
  • 3
  • 25
  • 36
Hussam Cheema
  • 536
  • 1
  • 7
  • 13
  • 3
    The Python interpreter makes optimisations as to where to look for variables depending on if it sees that variable being assigned to. The very existence of a line `x = ...` anywhere in a function/class changes the bytecode that Python generates to load `x` from `locals`, because there is no `y = ...` the bytecode generated loads `y` from `globals`. This is a good video to watch https://www.youtube.com/watch?v=DlgbPLvBs30&ab_channel=CodingTech – Iain Shelvington Feb 13 '21 at 10:51
  • @IainShelvington: but that means that python must read the entire text of the definition of `class A` before it executes the `print(x,y)`. I had thought that python just executed lines as they were read. – quamrana Feb 13 '21 at 10:53
  • 1
    @quamrana This variable lookup optimisation is pretty much the only "clever" thing the compiler does, for almost everything else your assumption is pretty safe – Iain Shelvington Feb 13 '21 at 10:54
  • 4
    @quamrana The parser *does* read the entire file before the *runtime* starts executing the code. The file is not read and executed line by line. – deceze Feb 13 '21 at 10:56
  • Thanks @deceze: I keep reading different explanations which seem to conflict with each other. Ok, so python *does* read the *entire* file, but the runtime only executes bits at a time, ie a function definition is *executed* by *creating* the function as an object, but a function itself is not executed unless the code also calls that function. – quamrana Feb 13 '21 at 11:04
  • 1
    @quamrana The parser turns the textual source code into a structure the computer can actually do something with. Part of that process is figuring out variables names and their scope. *Then* that structure is being evaluated and executed, at which point functions and classes are actually created as objects. Very generally speaking… – deceze Feb 13 '21 at 11:12
  • 1
    This is a relevant discussion: [How references to variables are resolved in Python](https://stackoverflow.com/questions/20246523/how-references-to-variables-are-resolved-in-python) – bb1 Feb 13 '21 at 13:13
  • 1
    By the way, I think your observation of the changes is wrong, on my machine assigning to whichever variable will use the global value of that variable, not others. – user202729 Feb 13 '21 at 14:53

1 Answers1

6

From the Python 3.9 documentation :

If a name binding operation occurs anywhere within a code block, all uses of the name within the block are treated as references to the current block.

The line x = 99 in the class definition, makes x local to the class block.

In a class block,

References follow the normal rules for name resolution with an exception that unbound local variables are looked up in the global namespace.

At the point the print(x,y) is executed, x is an unbound local variable. It's value is looked up in the global namespace, where x = 0.

When a name is used in a code block, it is resolved using the nearest enclosing scope.

When print(x, y) is executed, the value of y is looked up in the nearest enclosing scope, which is the body of def f(), where y = 1.

So print(x, y) outputs 0 1.

iBug
  • 35,554
  • 7
  • 89
  • 134
RootTwo
  • 4,288
  • 1
  • 11
  • 15