Python
Class Properties
Programming
Code Duplication
Python Tips

Print all properties of a Python Class

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

When people ask how to print all properties of a Python class, they often mean one of three different things: class attributes, instance attributes, or every accessible member including methods and inherited names. Python exposes each of those through a different introspection tool, so the first step is to decide exactly what you want to inspect.

Class Attributes Versus Instance Attributes

A Python class and a Python instance do not store data in the same place. Class attributes live on the class object, while instance attributes usually live in the instance __dict__.

The difference is easy to see:

python
1class User:
2    role = "member"
3
4    def __init__(self, name, active=True):
5        self.name = name
6        self.active = active
7
8
9print("Class attributes:")
10for key, value in vars(User).items():
11    if not key.startswith("__"):
12        print(key, value)
13
14user = User("Alice")
15print("\nInstance attributes:")
16for key, value in vars(user).items():
17    print(key, value)

vars(User) prints the class namespace, which includes methods and class-level values. vars(user) prints the data currently stored on that object instance. In most debugging scenarios, the instance view is what you actually want.

Using the Right Introspection Tool

Python gives you several built-in ways to inspect an object. They overlap, but they are not interchangeable.

vars(obj) is the cleanest option when you want the object's own stored attributes. It returns the attribute dictionary for objects that expose one.

dir(obj) returns a much broader list of names. It includes inherited members and special methods, which makes it useful for exploration but noisy for reporting.

inspect.getmembers(obj) gives you structured access to name and value pairs, which is useful when you want to filter precisely.

Here is a practical example with inspect:

python
1import inspect
2
3class User:
4    role = "member"
5
6    def __init__(self, name):
7        self.name = name
8        self.active = True
9
10    @property
11    def display_name(self):
12        return self.name.upper()
13
14    def greet(self):
15        return f"Hello, {self.name}"
16
17
18for name, value in inspect.getmembers(User):
19    if name.startswith("__"):
20        continue
21    if inspect.isroutine(value):
22        continue
23    print(name, value)

This prints non-method members from the class definition. Because inspect.getmembers resolves descriptors, it is often a better fit than vars when you want a richer reflection view.

Printing Only Useful Properties

In real projects, dumping everything is rarely the goal. Usually you want a concise list of public data attributes without methods or Python internals.

A small helper function makes that intent explicit:

python
1def print_public_data(obj):
2    for name in dir(obj):
3        if name.startswith("_"):
4            continue
5        value = getattr(obj, name)
6        if callable(value):
7            continue
8        print(f"{name}: {value}")
9
10
11class User:
12    role = "member"
13
14    def __init__(self, name):
15        self.name = name
16        self.login_count = 3
17
18    @property
19    def is_active(self):
20        return self.login_count > 0
21
22
23print_public_data(User("Alice"))

This approach is useful because it includes computed properties such as @property values, which vars(instance) would not show. That is often what people mean by "all properties" in the application sense.

Special Cases You Should Know

There are a few cases where the obvious approach fails.

Classes that use __slots__ may not have a normal instance dictionary, so vars(instance) can raise an error. In that case, you need to inspect the slot names directly.

Dataclasses are simpler. Their fields are explicit, and the dataclasses module gives you a clean API:

python
1from dataclasses import dataclass, asdict
2
3@dataclass
4class User:
5    name: str
6    active: bool
7
8
9user = User("Alice", True)
10print(asdict(user))

If your object is a dataclass, asdict is usually the most intention-revealing option.

Common Pitfalls

The biggest mistake is using dir and assuming every returned name is a user-defined property. Many names come from Python's object model and are irrelevant for normal debugging.

Another common error is confusing class inspection with instance inspection. vars(MyClass) and vars(my_instance) answer different questions, so the wrong call gives the wrong output even though the code technically works.

Be careful with getattr inside generic inspection helpers. Accessing a property may execute logic, perform I/O, or raise an exception. That matters if you are introspecting unknown objects.

It is also easy to miss descriptor-based attributes. @property values do not live in the instance dictionary, so vars(instance) alone will not show them.

Summary

  • Decide first whether you need class attributes, instance attributes, or all accessible members.
  • Use vars(instance) for direct instance data and vars(ClassName) for the class namespace.
  • Use inspect.getmembers when you need filtered, structured reflection.
  • Use dir only when broad discovery is more important than clean output.
  • Remember that properties, dataclasses, and __slots__ objects need slightly different handling.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

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

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.