2
votes

I'm trying to understand when Python code will refer to module-level variables versus class level variables. I have the following code in a module, main.py'

## main.py

# global variable x
x = "I am global and I love it!"

class SomeClass:
    x = "I am a class attribute, and life is good!"
    print(x)  # prints "I am a class attribute, and life is good!"
    def __init__(self):
        print(x)  # prints "I am global and I love it!"  Why?

print(x)  # prints "I am global and I love it!"
SomeClass()

When I import this module, the output is:

I am a class attribute, and life is good!
I am global and I love it!
I am global and I love it!

Why does the print inside the SomeClass.__init__ method print the global variable, while the print inside the class body prints the class attribute x?

This was paraphrased from a question on the Python mailing list: https://mail.python.org/pipermail/python-list/2015-December/701167.html

2

2 Answers

5
votes

Class definitions in Python create a namespace, but they do not create a new scope. This means that functions defined inside the class cannot access variables of the containing class directly. Instead they must access them as attributes of the class or an instance.

So, rather than accessing x in your example's __init__ function, you can get the class variable by using SomeClass.x or self.x.

The reason that print(x) works in the class body is that that code is running with the class namespace as its local namespace. There are a number of issues you can run into if you try to do more complicated stuff at class level though, as the scopeless namespace is a rather weird environment. For example, this will not work:

class Foo:
    x = 1
    dct = {i: x for i in range(10)}

You'll get a NameError about the x variable because the dictionary comprehension runs in its own scope and cannot see the class variable x, which is defined in the scopeless class namespace.

1
votes

Importing a module

Whenever you import a module, Python executes all the module-level code in the order the module is written. It attaches all the defined names to the module object, and the importer of the module can access all the defined names through the module object. That way you can import the module, and the names in the module don't clobber your namespace.

import main  # executes the script main.py, then creates a module
print(main.x)

Defining a class

You can think of the way that Python creates the class as similar to how it creates a module: it executes all the code in the class body, then assigns the defined names to the class. The __init__ method just becomes an attribute of the class, as well; by the time the function is called, the class has been constructed and within the function you can only refer to the x class attribute as SomeClass.x (or self.x inside of __init__). The namespace for the class definition is different than the namespace for the module, so the print(x) inside the class finds the class namespace first, since the print is in the same namespace.

Aside

Just as you can't refer to the current module when you're in, you cannot refer to the current class either. For example:

class SomeOtherClass:
    x = 5
    SomeOtherClass.x = 6  # This fails!

You can't refer to the class for the same reason you cannot refer to the module you are in from within a module: the name has not been created yet.

This answer was inspired by ChrisA's answer on the Python mailing list.