Python
class variables
list comprehension
programming
object-oriented programming

Accessing class variables from a list comprehension in the class definition

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

In Python, list comprehensions inside a class body can behave unexpectedly when they try to reference class variables defined in that same class body. The reason is scoping: comprehensions execute in their own local scope, not in the surrounding class namespace the way many people assume. Once you understand that rule, the workarounds are straightforward and predictable.

The Surprising Failure

Consider this class:

python
class Demo:
    base = 10
    values = [base + i for i in range(3)]

This raises a NameError because base is not looked up in the class body the way a normal class-level expression might suggest.

The important point is that the list comprehension creates a separate scope. That scope does not automatically see class-local names being defined in the class body.

Why Comprehensions Behave This Way

In Python 3, comprehensions have their own scope. This design avoids loop-variable leakage but also means they do not behave like a simple in-place class-body expression.

So inside:

python
class Demo:
    x = 5
    y = [x for _ in range(3)]

the x inside the comprehension is not resolved as a class-body local name. That is why the expression fails even though x appears to be defined just above it.

Simple Fix: Compute After Class Creation

The easiest and clearest solution is often to assign the derived class variable after the class is created.

python
1class Demo:
2    base = 10
3
4Demo.values = [Demo.base + i for i in range(3)]
5
6print(Demo.values)

This works because Demo now exists as a normal class object, and Demo.base is an ordinary attribute lookup.

Use a Helper Function in the Class Body

Another clean pattern is to use a helper function that takes the value explicitly.

python
1def build_values(base):
2    return [base + i for i in range(3)]
3
4class Demo:
5    base = 10
6    values = build_values(base)
7
8print(Demo.values)

This works because base is evaluated before the function call, and the comprehension runs inside the helper’s function scope, where base is a normal local variable.

Use a Class Method for Derived Values

If the derived list is conceptually part of class construction logic, a class method can be clearer.

python
1class Demo:
2    base = 10
3
4    @classmethod
5    def build_values(cls):
6        return [cls.base + i for i in range(3)]
7
8Demo.values = Demo.build_values()
9print(Demo.values)

This is often a good choice when the derived data depends on several class attributes.

Do Not Confuse Class Scope with Function Scope

Normal expressions in the class body can access previously defined class-level names:

python
class Demo:
    a = 2
    b = a + 3

This works. The confusion comes specifically from the special scoping behavior of comprehensions, generator expressions, and similar constructs.

That distinction is the key rule to remember.

Tuple Literals and Plain Expressions Are Different

If you do not need a comprehension, plain expressions are fine:

python
class Demo:
    base = 10
    values = (base, base + 1, base + 2)

The scoping problem appears when the comprehension body executes in its own scope.

Practical Design Advice

If a class variable depends on computation, choose clarity over cleverness.

Prefer:

  • A helper function.
  • A post-class assignment.
  • A class method.

Do not try to outsmart comprehension scope rules inside the class body unless the pattern is already familiar to the whole team.

Testing the Behavior

A short test helps document the expected class-level result:

python
1class Config:
2    base = 3
3
4def build(base):
5    return [base * i for i in range(4)]
6
7Config.values = build(Config.base)
8
9assert Config.values == [0, 3, 6, 9]

This is clearer than relying on subtle class-scope behavior that future maintainers may misread.

Common Pitfalls

  • Assuming list comprehensions see class-local names the same way plain expressions do.
  • Treating the failure as a random Python bug rather than a scope rule.
  • Writing clever class-body expressions that future readers will not understand.
  • Forgetting that generator expressions and comprehensions have similar scope behavior.
  • Forcing everything into class-level constants when a helper function would be clearer.

Summary

  • In Python 3, comprehensions inside a class body run in their own scope.
  • That scope does not automatically resolve class variables being defined in the class body.
  • Plain class-body expressions can access earlier class names, but comprehensions are different.
  • Use helper functions, class methods, or post-class assignments to build derived class values.
  • Favor explicit patterns over subtle scope-dependent tricks.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms