Reputation: 71
(Python 3.5.2)
I have defined __repr__
for one of my classes as follows:
class d():
def __init__(self):
self._values = []
return
def __pos__(self):
return self._values[0]
def __repr__(self, value):
self._values.append(value)
return
Now I want
x = d()
print(x,"a")
print(+x)
to return
a
but instead I get
TypeError: __repr__() missing 1 required positional argument: 'value'
I've tried a few variations such as print(x),"a"
with no luck.
Upvotes: 3
Views: 9903
Reputation: 530843
If you want to control how an instance of your class is displayed, the right way to do that is to override the __format__
method. In general, the three methods you can override are used to:
__repr__
- used when the object needs to be displayed in the interactive interpreter, usually as a debugging aid. As far as possible, it should be a string that could recreate the object if evaluated.__str__
- used when the object is passed to str
or called when print
attempts to display your object. Without another definition, it simply calls __repr__
. This is the "default" string representation for an instance.__format__
- used when your object is an argument to str.format
. It receives as an additional argument the format specification (if any) that appears after the optional :
in a replacement field.Here is a simple example of a class to represent pairs of numbers. The character used to separate the numbers can be configured via the format specification.
class Pair():
def __init__(self, x, y):
self.x = x
self.y = y
def __format__(self, spec):
return "{}{}{}".format(self.x, spec, self.y)
def __str__(self):
return "{:/}".format(self)
def __repr__(self):
return "Pair({}, {})".format(self.x, self.y)
It can be used as follows:
>>> x = Pair(1,2)
>>> x # using __repr__
Pair(1, 2)
>>> str(x) # using __str__, with a default separator of /
'1/2'
>>> print(x) # uses __str__ implicitly
1/2
>>> "{}".format(x) # no separator specified
'12'
>>> "{:-}".format(x) # use - to separate the two numbers
'1-2'
Note that in the case of format
, the spec is not necessarily part of the return value, but acts as an instruction on how to format the value.
Upvotes: 22
Reputation: 1093
There are a few people saying you should never add arguments to __str__
or __repr__
but I disagree.
For example, if you want to display the string representation of a class's objects you would write a custom __str__
. But what if some of the objects were really long? Sometimes you may want to truncate those objects, sometimes you may want them in full.
class Compute:
def __init__(self, foo, ...):
self.foo = foo
...
def __str__(self, trunc=False):
return_str = ''
for item in self.__dict__:
if trunc:
# If the length of the str representation of the item is long, shorten it.
return_str += f'\n{item} = {self.__dict__[item] if len(str(self.__dict__[item] < 50) else str(self.__dict__[item])[:51]}'
else:
# This would be whatever your usual __str__ method returns
return_str += f'\n{item} = {self.__dict__[item]}'
return return_str
You would call this simply using:
bar = Compute(foo=...)
print(bar.__str__(trunc=True))
Now, if your __init__
contains any objects whose length as a string is particularly long, (say you've got a large list of data) it will only print up to the 51st character.
You can add a lot more logic to how you want the truncated strings to be printed too.
I would recommend having default arguments set to False in the dunder method. This means that unless explicitly asked for, the __str__
method can behave normally.
I have used this when I wanted to print a class's objects both to the terminal and to a log file. I only wanted them printed in full to the log file, and a truncated version to the terminal so I wrote something similar to this.
Hope this helps.
Upvotes: 12
Reputation: 22953
Your using __repr__
the wrong way. __repr__
should be used to return a representation of your object in a printable, formatted way. As opposed to Python simply printing the name and memory address of your object. Per the documentation of __repr__
:
Called by the
repr()
built-in function to compute the “official” string representation of an object. If at all possible, this should look like a valid Python expression that could be used to recreate an object with the same value (given an appropriate environment). If this is not possible, a string of the form <...some useful description...> should be returned. The return value must be a string object. If a class defines__repr__()
but not__str__()
, then__repr__()
is also used when an “informal” string representation of instances of that class is required.
I'm really not sure what your trying to achive with using __repr__
though. If you simply want add an element to self.values
via a method of d
, ditch the magic methods and just create your own:
class d():
def __init__(self):
self._values = []
def __pos__(self):
return self._values[0]
def append(self, value): # create your won function
self._values.append(value)
Upvotes: 2