Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to print an object's representation using the string format function?

I'm creating a Money class, and I'd like to pass the object directly to the string format() function and get the money representation with 2 decimals and the currency symbol.

What method should I override to print with the string format function? Overriding str and repr did not work.

from decimal import Decimal


class Money(Decimal):
    def __str__(self):
        return "$" + format(self, ',.2f')

    def __repr__(self):
        return "$" + format(self, ',.2f')

m = Money("123.44")
print(m) # $123.44. Good.
m        # $123.44. Good.
print("Amount: {0}".format(m)) # 123.44. Bad. I wanted $123.44
print(f"Amount: {m}") # 123.44. Bad. I wanted $123.44
like image 696
Jesus H Avatar asked Jan 03 '23 13:01

Jesus H


1 Answers

You can give your class a __format__ method; in this case just call overridden version:

def __format__(self, spec):
    spec = spec or ',.2f'  # set a default spec when not explicitly given
    return '$' + super().__format__(spec)

From the linked documentation:

Called by the format() built-in function, and by extension, evaluation of formatted string literals and the str.format() method, to produce a “formatted” string representation of an object. The format_spec argument is a string that contains a description of the formatting options desired. The interpretation of the format_spec argument is up to the type implementing __format__(), however most classes will either delegate formatting to one of the built-in types, or use a similar formatting option syntax.

You'll want to drop your __str__ and __repr__ implementations now, or at least not add another '$' on top of the one __format__ now adds (which format(self, ...) will trigger).

Demo:

>>> from decimal import Decimal
>>> class Money(Decimal):
...     def __format__(self, spec):
...         spec = spec or ',.2f'  # set a default spec when not explicitly given
...         return '$' + super().__format__(spec)
...
>>> m = Money("123.44")
>>> print("Amount: {0}".format(m))
Amount: $123.44
>>> print(f"Amount: {m}")
Amount: $123.44
like image 50
Martijn Pieters Avatar answered Jan 19 '23 01:01

Martijn Pieters