Consider:
class Base:
def __init__(self):
self.__repr__ = lambda: "String!"
class Child(Base):
pass
c = Child()
print(f"{c}")
print(f"{c.__repr__()}")
This results in:
<__main__.Child object at 0x7f07cd88f850>
String!
I get the same output when changing the __str__
and __format__
methods. I would like for Child
's representation in an f-string to be just "String!"
, but changing __str__
, __repr__
, and __format__
doesn't achieve this.
What does Python use to determine what's displayed in an f-string if not the instance's __repr__
or either of the other two methods?
Python magic methods (i.e., methods like __str__
, __repr__
, and __format__
) are looked up on the object's type, not the object itself (see: Special method lookup), and doing something like self.__repr__ = lambda: "String!"
changes the dictionary of the instance (not the class itself). Given the above example, c.__dict__
results in:
{'__repr__': <function Base.__init__.<locals>.<lambda> at 0x7f07cd81de10>}
That is, we've changed the dictionary of the instance to include __repr__
, but haven't actually changed the instance's special function (which is looked up on the class itself, not any individual instance of said class). So when the instance is represented on an f-string, the special function is used. The correct thing to do would be something like:
class Base:
def __repr__(self):
return "String!"
class Child(Base):
pass
c = Child()
print(f"{c}")
Which outputs:
String!