Is there a way to auto generate a __str__() implementation in python?

Question:

Being tired manually implementing a string representation for my classes, I was wondering if there is a pythonic way to do that automatically.

I would like to have an output that covers all the attributes of the class and the class name. Here is an example:

class Foo(object):
    attribute_1 = None
    attribute_2 = None
    def __init__(self, value_1, value_2):
         self.attribute_1 = value_1
         self.attribute_2 = value_2

Resulting in:

bar = Foo("baz", "ping")
print(str(bar)) # desired: Foo(attribute_1=baz, attribute_2=ping)

This question came to mind after using Project Lombok @ToString in some Java projects.

Asked By: Marco Ferrari

||

Answers:

You can iterate instance attributes using vars, dir, …:

def auto_str(cls):
    def __str__(self):
        return '%s(%s)' % (
            type(self).__name__,
            ', '.join('%s=%s' % item for item in vars(self).items())
        )
    cls.__str__ = __str__
    return cls

@auto_str
class Foo(object):
    def __init__(self, value_1, value_2):
        self.attribute_1 = value_1
        self.attribute_2 = value_2

Applied:

>>> str(Foo('bar', 'ping'))
'Foo(attribute_2=ping, attribute_1=bar)'
Answered By: falsetru

wrote this while falsetru answerred.
Its the same idea, mine is very beginner friendly in terms of reading it, his is much nicer implemented imho

class stringMe(object):
        def __str__(self):
            attributes = dir(self)
            res = self.__class__.__name__ + "("
            first = True
            for attr in attributes:
                if attr.startswith("__") and attr.endswith("__"):
                    continue

                if(first):
                    first = False
                else:
                    res += ", "

                res += attr + " = " + str( getattr(self, attr))

            res += ")"
            return res

    class Foo(stringMe):
        attribute_1 = None
        attribute_2 = None
        def __init__(self, value_1, value_2):
             self.attribute_1 = value_1
             self.attribute_2 = value_2


bar = Foo("baz", "ping")
print(str(bar)) # desired: Foo(attribute_1=baz, attribute_2=ping)
Answered By: Henrik

You can use @dataclass, which automatically generates __init__(), __repr__(), __str__(), and more. You just need to add a @dataclass decorator to your class and add type annotations to the members. You can even remove your __init__() implementation then.

from dataclasses import dataclass

@dataclass
class Foo(object):
    attribute_1 : str
    attribute_2 : str

bar = Foo("baz", "ping")
print(str(bar)) # Prints: Foo(attribute_1='baz', attribute_2='ping')
Answered By: sirain
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.