19.3. OOP Format
Calling function
format(obj, fmt)
callsobj.__format__(fmt)
Method
obj.__format__()
must returnstr
Used for advanced formatting in f-strings (
f'...'
)
19.3.1. Example
>>> class Astronaut:
... def __init__(self, name):
... self.name = name
...
... def __format__(self, mood):
... if mood == 'happy':
... return f"Yuppi, we're going to space!"
... elif mood == 'scared':
... return f"I hope we don't crash"
>>>
>>>
>>> jose = Astronaut('José Jiménez')
>>>
>>> print(f'{jose:happy}')
Yuppi, we're going to space!
>>>
>>> print(f'{jose:scared}')
I hope we don't crash
19.3.2. Use Case - 1
ares3_landing = datetime(2035, 11, 7)
ares3_start = datetime(2035, 6, 29)
ares3_duration = timedelta(days=557, seconds=80025)
>>> SECOND = 1
>>> MINUTE = 60 * SECOND
>>> HOUR = 60 * MINUTE
>>> DAY = 24 * HOUR
>>> WEEK = 7 * DAY
>>> MONTH = 30.4375 * DAY
>>> YEAR = 365.25 * DAY
>>> SOL = 24*HOUR + 39*MINUTE + 35.244*SECOND
>>>
>>>
>>> class Mission:
... def __init__(self, name, duration):
... self.name = name
... self.duration = duration
...
... def __format__(self, unit):
... duration = self.duration
... match unit:
... case 's' | 'second' | 'seconds': duration /= SECOND
... case 'm' | 'minute' | 'minutes': duration /= MINUTE
... case 'h' | 'hour' | 'hours': duration /= HOUR
... case 'd' | 'day' | 'days': duration /= DAY
... case 'w' | 'week' | 'weeks': duration /= WEEK
... case 'mth'| 'month' | 'months': duration /= MONTH
... case 'y' | 'year' | 'years': duration /= YEAR
... case 'sol': duration /= SOL
... case _: raise ValueError(f'Unknown unit')
... return f'{duration:.1f} {unit}'
>>>
>>>
>>> ares3 = Mission('Ares III', duration=543*SOL)
>>>
>>> print(f'{ares3.name} mission to Mars took {ares3:seconds}')
Ares III mission to Mars took 48204957.5 seconds
>>>
>>> print(f'{ares3.name} mission to Mars took {ares3:minutes}')
Ares III mission to Mars took 803416.0 minutes
>>>
>>> print(f'{ares3.name} mission to Mars took {ares3:hours}')
Ares III mission to Mars took 13390.3 hours
>>>
>>> print(f'{ares3.name} mission to Mars took {ares3:days}')
Ares III mission to Mars took 557.9 days
>>>
>>> print(f'{ares3.name} mission to Mars took {ares3:weeks}')
Ares III mission to Mars took 79.7 weeks
>>>
>>> print(f'{ares3.name} mission to Mars took {ares3:months}')
Ares III mission to Mars took 18.3 months
>>>
>>> print(f'{ares3.name} mission to Mars took {ares3:years}')
Ares III mission to Mars took 1.5 years
19.3.3. Use Case - 2
Temperature conversion
>>> class Temperature:
... def __init__(self, kelvin):
... self.kelvin = kelvin
...
... def to_fahrenheit(self):
... return (self.kelvin-273.15) * 1.8 + 32
...
... def to_celsius(self):
... return self.kelvin - 273.15
...
... def __format__(self, unit):
... match unit:
... case 'K' | 'kelvin': value = self.kelvin
... case 'C' | 'celsius': value = self.to_celsius()
... case 'F' | 'fahrenheit': value = self.to_fahrenheit()
... unit = unit[0].upper()
... return f'{value:.2f} {unit}'
>>>
>>>
>>> temp = Temperature(kelvin=309.75)
>>>
>>>
>>> print(f'Temperature is {temp:kelvin}')
Temperature is 309.75 K
>>>
>>> print(f'Temperature is {temp:celsius}')
Temperature is 36.60 C
>>>
>>> print(f'Temperature is {temp:fahrenheit}')
Temperature is 97.88 F
19.3.4. Use Case - 3
Format output
>>> from dataclasses import dataclass
>>> import json
>>>
>>>
>>> @dataclass
... class Point:
... x: int
... y: int
... z: int = 0
...
... def __format__(self, format):
... match format:
... case 'repr': result = f"Point(x={self.x}, y={self.y}, z={self.z})"
... case 'dict': result = vars(self)
... case 'tuple': result = tuple(vars(self).values())
... case 'json': result = json.dumps(vars(self))
... return str(result)
>>>
>>>
>>> point = Point(x=1, y=2)
>>>
>>>
>>> print(f'{point:repr}')
Point(x=1, y=2, z=0)
>>>
>>> print(f'{point:tuple}')
(1, 2, 0)
>>>
>>> print(f'{point:dict}')
{'x': 1, 'y': 2, 'z': 0}
>>>
>>> print(f'{point:json}')
{"x": 1, "y": 2, "z": 0}
19.3.5. Use Case - 1
status "Full Health" - when health 100%
status "Injured" - when health 75% - 100% (exclusive)
status "Badly Wounded" - when health 25% - 75% (exclusive)
status "Near Death" - when health 1% - 25% (exclusive)
status "Dead" - when health 0% or less
>>> from dataclasses import dataclass
>>>
>>>
>>> @dataclass
... class Hero:
... name: str
... health: int = 100
... health_full: int = 100
...
... def _get_status(self):
... percent = int(self.health / self.health_full * 100)
... if percent == 100: return 'full health'
... if percent in range(75, 100): return 'injured'
... if percent in range(25, 75): return 'badly wounded'
... if percent in range(1, 25): return 'near death'
... if percent <= 0: return 'dead'
...
... def __format__(self, what):
... match what:
... case 'status': return self._get_status()
... case 'name': return self.name
... case _: return self.name
>>>
>>>
>>> hero = Hero('Pan Twardowski')
>>> hero.health = 100
>>> print(f'{hero:name} is {hero:status}')
Pan Twardowski is full health
>>> hero.health = 90
>>> print(f'{hero:name} is {hero:status}')
Pan Twardowski is injured
>>> hero.health = 50
>>> print(f'{hero:name} is {hero:status}')
Pan Twardowski is badly wounded
>>> hero.health = 10
>>> print(f'{hero:name} is {hero:status}')
Pan Twardowski is near death
>>> hero.health = 0
>>> print(f'{hero:name} is {hero:status}')
Pan Twardowski is dead
19.3.6. Assignments
# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author
# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`
# %% About
# - Name: Operator String Format
# - Difficulty: easy
# - Lines: 8
# - Minutes: 5
# %% English
# 1. Overload `format()`
# 2. Has to convert length units: km, cm, m
# 3. Round result to one decimal place
# 4. Run doctests - all must succeed
# %% Polish
# 1. Przeciąż `format()`
# 2. Ma konwertować jednostki długości: km, cm, m
# 3. Wynik zaokrąglij do jednego miejsca po przecinku
# 4. Uruchom doctesty - wszystkie muszą się powieść
# %% Hints
# - 1 km = 1000 m
# - 1 m = 100 cm
# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'
>>> result = Distance(meters=1337)
>>> format(result, 'km')
'1.3 km'
>>> format(result, 'cm')
'133700.0 cm'
>>> format(result, 'm')
'1337.0 m'
"""
METER = 1
CENTIMETER = METER * 0.01
KILOMETER = METER * 1000
class Distance:
meters: int | float
def __init__(self, meters):
self.meters = meters