When I try to use the print() function on an instance of my custom Python class, I just get a generic memory address like <__main__.MyClass object at 0x...> instead of the actual data. Is there a way to override this default behavior so that it prints the object's attributes in a readable format? I've seen mentions of dunder methods—should I be using __str__ or __repr__ for this, and what is the specific difference between them when debugging?
3 answers
To change how an object is printed, you need to implement the __str__ or __repr__ methods within your class. The print() function primarily looks for __str__, which is meant to provide a "user-friendly" or informal string representation. If __str__ is not defined, Python falls back to __repr__. A good rule of thumb is to always implement __repr__ first, as it is used for debugging and should ideally be an unambiguous representation that looks like the code used to create the object. For example, def __str__(self): return f"{self.name} (${self.price})" would provide a clean output for end-users, while def __repr__(self): return f"Product(name='{self.name}', price={self.price})" is better for developer logs.
Does this mean that if I only define __repr__, the print() function will still work and show that technical representation, or will it still revert to the memory address if __str__ is missing from the class definition?
I always suggest implementing both. Use __str__ for the pretty version you want users to see and __repr__ for the detailed version you need when your code crashes and you're looking at logs.
I agree with Barbara. Having that distinction makes it so much easier to build professional applications where the internal state of the object is hidden from the UI but remains perfectly clear for the developer.
You are exactly right, Michael. If you only define __repr__, Python will use it as a backup for the print() function and str() calls. It’s actually a common "best practice" to define __repr__ first because it ensures you never see those cryptic memory addresses again, even when looking at your objects inside a list or a dictionary where Python prefers the developer-focused output.