Python
Object-Oriented Programming
Class Properties
Iteration
Programming Tips

How to loop through all the properties of a class?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In Python, the right way to loop through all the “properties” of a class depends on what you actually mean by properties. Most of the time, people want the instance attributes stored on an object, and the cleanest way to iterate over those is with vars or __dict__.

Iterate Over Instance Attributes

For normal Python objects, instance data is usually stored in the object dictionary.

python
1class User:
2    def __init__(self, name, age):
3        self.name = name
4        self.age = age
5        self.active = True
6
7user = User("Ada", 36)
8
9for key, value in vars(user).items():
10    print(key, value)

That prints each attribute name and value currently stored on the instance.

You can write the same thing with user.__dict__.items(), but vars(user) is a little cleaner and signals intent more clearly.

Understand the Difference Between Class and Instance Data

It is important to separate instance attributes from class attributes.

python
1class Config:
2    app_name = "Demo"
3
4    def __init__(self, debug):
5        self.debug = debug
6
7cfg = Config(True)
8
9print(vars(cfg))
10print(Config.app_name)

vars(cfg) includes debug, because that value belongs to the instance. It does not automatically include app_name, because that value lives on the class object itself.

If you want class-level names too, you need a different form of inspection.

Include Class-Level Attributes Carefully

To inspect names defined on the class, you can use vars on the class object.

python
1class Config:
2    app_name = "Demo"
3    version = 3
4
5    def __init__(self, debug):
6        self.debug = debug
7
8for key, value in vars(Config).items():
9    if not key.startswith("__"):
10        print(key, value)

That will include class attributes and methods. Because of that, you often need filtering if you only want data fields.

Real @property Descriptors Are Different

Python’s @property feature creates computed attributes, not entries in __dict__.

python
1class Rectangle:
2    def __init__(self, width, height):
3        self.width = width
4        self.height = height
5
6    @property
7    def area(self):
8        return self.width * self.height
9
10rect = Rectangle(4, 5)
11print(rect.area)

The area value is available on the instance, but it does not appear in vars(rect) because it is computed through the class definition.

If you need to discover @property descriptors, inspect the class:

python
for key, value in vars(Rectangle).items():
    if isinstance(value, property):
        print(key, getattr(rect, key))

That pattern finds property descriptors on the class and then reads their values from the instance.

Dataclasses Make Iteration Cleaner

If the class is a dataclass, the standard library gives you field metadata directly.

python
1from dataclasses import dataclass, fields
2
3@dataclass
4class User:
5    name: str
6    age: int
7    active: bool
8
9user = User("Ada", 36, True)
10
11for field in fields(user):
12    print(field.name, getattr(user, field.name))

This is often the best option when you control the class design and want predictable introspection.

Watch Out for __slots__

Some classes use __slots__ instead of an instance dictionary. In that case, vars(obj) may not work because there is no __dict__.

python
1class Point:
2    __slots__ = ("x", "y")
3
4    def __init__(self, x, y):
5        self.x = x
6        self.y = y
7
8p = Point(2, 3)
9
10for name in Point.__slots__:
11    print(name, getattr(p, name))

So the “loop through all properties” answer is partly about class design, not just syntax.

Common Pitfalls

A common mistake is using dir(obj) and assuming it returns only data fields. dir returns many names, including methods and inherited members, so it is usually too broad for simple attribute iteration.

Another pitfall is forgetting the difference between instance attributes, class attributes, and computed properties. They live in different places and need different inspection techniques.

Be careful with getattr on computed properties as well. Accessing a property can run code, which may be expensive or have side effects.

Finally, if you just need serialization, do not over-engineer reflection. For plain objects, vars(obj) is often all you need.

Summary

  • Use vars(obj).items() to iterate over normal instance attributes.
  • Use vars(MyClass) if you need to inspect class-level names.
  • '@property descriptors live on the class, not in the instance dictionary.'
  • Dataclasses provide a clean field API through dataclasses.fields.
  • Classes with __slots__ need a different approach because they may not have __dict__.

Course illustration
Course illustration

All Rights Reserved.