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.
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)'
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)
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')
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.
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)'
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)
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')