Objektumok karakterlánc-reprezentációját alapvetően a str() és repr() függvényekkel kaphatjuk meg. Azt, hogy ezek mit adjanak vissza, az egyéni osztályainkban a __str__ és __repr__ metódusok implementálásával határozhatjuk meg. A karakterlánc-reprezentációt a format() beépített függvénnyel is előállíthatjuk, amelynél arra is lehetőség van, hogy különböző formátumokat kapjunk attól függően, hogy második argumentumként milyen formátumkódot adunk meg. Szám- és karakterlánctípusok megjelenési formátumának meghatározására a Python egy szabványos formázási kódrendszert definiál „formátum meghatározó mini-nyelv” (Format Specification Mini-Language) névvel hivatkozva.
Formátum meghatározó kódok nem csak a format() függvényben, hanem a str.format() metódusban, sőt formázott karakterlánc-literál vagy röviden f-string esetén is használhatók.
A format() függvény nem tesz mást, mint az első argumentumként megadott objektumra meghívja a __format__ speciális metódust átadva a formátumkódokat. A __format__ metódust az egyéni osztályunkban felülírhatjuk és a __str__ és __repr__ által visszaadottakon felül, egyéni karakterlánc-reprezentációkat határozhatunk meg az osztálypéldányokra. Erre mutatnak különböző példákat az alábbi osztálydefiníciók, amelyeknél a példányok egyéni formátumkódokkal meghatározott karakterlánc-reprezentációit a fentebb említett három módon (format() függvénnyel, str.format() metódussal és formázott karakterlánc-literállal) állítottuk elő.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
from collections import namedtuple class Point(namedtuple('PointNT', 'x, y')): def __format__(self, fmt:str): """Az x és y koordináták a standard számformátumkódokkal jeleníthetők meg.""" if fmt: return f'{type(self).__name__}(x={self.x:{fmt}}, y={self.y:{fmt}})' # Ha nem adunk meg egyéni formázást, akkor a formázás az alaposztály szerinti lesz. return super().__format__(fmt) # TESZT p = Point(12, 3.456) print(p) # Eredmény: Point(x=12, y=3.456) print(format(p)) # Eredmény: Point(x=12, y=3.456) print(format(p, '.1f')) # Eredmény: Point(x=12.0, y=3.5) |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
from math import atan2, degrees from dataclasses import dataclass @dataclass class Point: x: int | float y: int | float def __format__(self, fmt: str): """Megadható egyéni formátum-karakterláncok: 'polar_rad' és 'polar_deg'. A visszaadott karakterláncban a pont origótól mért r abszolútértéke, valamint φ irányszöge jelenik meg. A 'polar_rad' esetén az irányszög radiánban, a 'polar_deg' estében fokban értendő. A 'polar_rad' vagy 'polar_deg' után vesszővel elválasztava lehet megadni az r és φ számok formátumát a standard formátumkódokkal. Példák: 1) mind az r, mind a φ számértékeket formázzuk: 'polar_rad, .2f, .1f' 'polar_deg, .3f, g' 2) csak az r éréket formázzuk: 'polar_deg,.2f' 3) csak a φ értéket formázzuk: 'polar_deg, , .2f' """ if fmt.startswith('polar'): r, phi = pow(self.x ** 2 + self.y ** 2, 0.5), atan2(self.y, self.x) # A formátum-karakterlánc részekre bontása. parts = [k.strip() for k in fmt.strip().split(',')] # Az r és φ formátumkódjainak elkülönítése. fc_r = fc_phi = '' if len(parts) == 2: fc_r = parts[1] if len(parts) == 3: fc_r, fc_phi = parts[1:3] # A formázott karakterlánc-reprezentáció előállítása és ezzel visszatérés. if parts[0] == 'polar_rad': return f'Point(r = {r:{fc_r}}, φ = {phi:{fc_phi}} rad)' elif parts[0] == 'polar_deg': return f'Point(r = {r:{fc_r}}, φ = {degrees(phi):{fc_phi}} deg)' # Ha nem adunk meg egyéni formázást, akkor a formázás az alaposztály szerinti lesz. return super().__format__(fmt) # TESZT p = Point(+100, +100) print(format(p)) # Eredmény: Point(x=100, y=100) print("{0:{1}}".format(p, 'polar_rad, .2f, .3f')) # Eredmény: Point(r = 141.42, φ = 0.785 rad) print("{0:{1}}".format(p, 'polar_deg')) # Eredmény: Point(r = 141.4213562373095, φ = 45.0 deg) print("{0:{1}}".format(p, 'polar_deg, .2f, g')) # Eredmény: Point(r = 141.42, φ = 45 deg) print("{0:{1}}".format(p, 'polar_deg, , g')) # Eredmény: Point(r = 141.4213562373095, φ = 45 deg) print("{0:{1}}".format(p, 'polar_deg, e')) # Eredmény: Point(r = 1.414214e+02, φ = 45.0 deg) |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
from enum import Enum class Color(Enum): RED = 0 GREEN = 1 BLUE = 2 YELLOW = 3 MAGENTA = 4 AQUA = 5 WHITE = 6 def __format__(self, fmt): """Az 'RGB' vagy 'rgb' formátumkód hatására a felsorolástípus színkonstansainak karakterlánc-reprezentációjában a szín neve és zárójelben az RGB koordinátái jelennek meg. """ if fmt.lower() == 'rgb': rgb_values = [(255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 0), (255, 0, 255), (0, 255, 255), (255, 255, 255)] return ' '.join((self.name, str(rgb_values[self.value]))) # Ha nem adunk meg egyéni formázást, akkor a formázás az alaposztály szerinti lesz. return super().__format__(fmt) # TESZT # A felsorolástípus színkonstansainak megjelenítése standard és egyéni formátumkódokkal. for color in Color: print(f"{color:{'<15'}}{color:{'RGB'}}") # Eredmény: # Color.RED RED (255, 0, 0) # Color.GREEN GREEN (0, 255, 0) # Color.BLUE BLUE (0, 0, 255) # Color.YELLOW YELLOW (255, 255, 0) # Color.MAGENTA MAGENTA (255, 0, 255) # Color.AQUA AQUA (0, 255, 255) # Color.WHITE WHITE (255, 255, 255) |
A szabványos könyvtárban is találkozhatunk objektumok egyéni formátumkódokkal történő megjelenítési lehetőségével. Ilyen például az ipaddress modulban az ip cím különféle formátumban történő karakterlánc-reprezentációja.
A Python tudásépítés lépésről lépésre című e-könyvben a karakterláncok formázásáról és a standard formátumkódokról részletesen a „Karakterláncok formázása” fejezet „Formázott karakterlánc-literál” alfejezetében olvashatunk. A format() függvénnyel a „Beépített függvények” fejezetben ismerkedhetünk meg. A __format__ metódusról a „Mágikus metódusok egyedi igényre szabott osztályokban” című fejezetben van szó a mostani bejegyzésben szereplőktől eltérő példával bemutatva a használatát. A mezőneves tuple (namedtuple) a „Készétel fogyasztás – a szabványos könyvtár moduljainak használata” fejezet „Speciális konténer típusok” alfejezetében kerül részletes ismertetésre. Az adatosztályokat (dataclass) és a felsorolástípust (Enum) pedig a „Különleges osztálydefiníciók” fejezet tárgyalja szintén részletesen, számos példával segítve a megértésüket.