Arcade-pelien ohjelmointi
Pythonilla ja Pygamella

Chapter 20: Tekstien muotoilukoodit

Alla on taulukoituna tekstin muotoilukoodit. Yksityiskohtainen selitys koodeille seuraa alla.

Number Format Output Description
3.1415926 {:.2f} 3.14 2 decimal places
3.1415926 {:+.2f} +3.14 2 decimal places with sign
-1 {:+.2f} -1.00 2 decimal places with sign
3.1415926 {:.0f} 3 No decimal places (will round)
5 {:0>2d} 05 Pad with zeros on the left
1000000 {:,} 1,000,000 Number format with comma separator
0.25 {:.2%} 25.00% Format percentage
1000000000 {:.2e} 1.00e+09 Exponent notation
11 {:>10d}         11 Right aligned
11 {:<10d} 11 Left aligned
11 {:^10d}     11 Center aligned

20.1 Kokonaisluvut

Kopioi ja aja seuraava ohjelma, joka tulostaa useita satunnaislukuja.

import random

for i in range(10):
    x = random.randrange(20)
    print(x)

Tulostuksessa luvut tasataan vasemmalle ja ulkoasu ei ole kovin hyvä:

16
13
2
0
10
3
18
1
14
5

Tulostus saadaan näyttämään paremmalta käyttämällä muotoilukoodia ja tasaamalla luvut oikealle. Ensimmäiseksi käytämme format komentoa merkkijonossa, ks. alla:

import random

for i in range(10):
    x = random.randrange(20)
    print("{}".format(x) )

Tämä on askel parempaan, mutta ei kuitenkaan vielä valmis. Katso, miten merkkijono päättyy .format(x)kanssa. Kaikki merkkijonot ovat itse asiassa luokan String olioita. Tässä luokassa on kutsuttavia metodeja, joista yksi on format.

format funktio ei tulosta aaltosulkeita {} vaan ne korvataan arvolla x. Alla koodi näyttää kuitenkin vielä samalta kuin aiemmin.

7
15
4
12
3
8
7
15
12
8

Lukujen oikealle tasaamiseen tarvitaan aaltosulkeiden {} väliin lisää informaatiota:

import random

for i in range(10):
    x = random.randrange(20)
    print("{:2}".format(x) )

Tulostus:

 7
15
 4
12
 3
 8
 7
15
12
 8

Nyt näyttää paremmalta. Luvut on tasattu oikealle, mutta mikä tämän sai aikaan? Luku :2 on lisättynä aaltosulkeisiin, mutta ei kuitenkaan aivan 'lonkalta'.

Tässä tarkempi selitys: Aaltosulkeilla { } kerromme tietokoneelle, että käytämme lukujen muotoilua. Kaksoispisteen : jälkeen suluissa on muotoiluinformaationa luku 2, joka määrittelee kentän leveyden kahden merkin kokoiseksi. Tämä varaa tulostukselle siis aina kahden merkin kokoisen kentän, vaikka tulostus olisikin yhden merkin kokoinen. Oletuksena tämä muotoilu tasaa luvut oikealle ja tekstin vasemmalle.

Eikä tässä tarvita kutsua str( ) funktioon luvun muuntamiseksi tekstiksi, joten sen voi hyvin jättää pois.

Miten suurempien lukujen kanssa toimitaan? Tehdään kokeeksi suurempia satunnaislukuja:

import random

for i in range(10):
    x = random.randrange(100000)
    print("{:6}".format(x) )

Tämä saa aikaan kelvollisen tulostuksen oikealle tasattuna:

 18394
 72242
 97508
 21583
 11508
 76064
 88756
 77413
  7930
 81095
 

Jos tulostukseen haluttaisiin amerikkalaiseen tapaan tuhaterottimeksi pilkku, niin se on lisättynä alla olevassa koodissa:

import random

for i in range(10):
    x = random.randrange(100000)
    print("{:6,}".format(x) )

The output:

65,732
30,248
13,802
17,177
 3,584
 7,598
21,672
82,900
72,838
48,557

Muotoilukoodiin lisättiin pilkku kentän leveyden määrityksen jälkeen. Se kirjoitetaan kenttäleveyden jälkeen, ei ennen. Pilkkumerkki luetaan mukaan kentän leveyteen. Esimerkiksi, 1,024 on leveydeltään 5, ei 4.

Voimme tulostaa moninaisia arvoja ja yhdistää niitä tekstiin. Kopioi ja aja alla oleva koodi.

x = 5
y = 66
z = 777
print("A - '{}' B - '{}' C - '{}'".format(x, y, z))

Ohjelma korvaa luvut aaltosulkeiden paikalle format-funktion parametreilla x, y ja z:

A - '5' B - '66' C - '777'

Jos aaltosuljepareja on kolme, ohjelma odottaa kolmea arvoa listattuna format funktion parametreiksi. Ensinnä annettu korvaa ensimmäisen suljeparin.

Toisinaan haluamme tulostaa saman arvon useaan kertaan tai eri järjestyksessä. Järjestys voidaan määrittää aaltosulkeiden sisään kirjoitettavalla järjestysnumerolla.

x = 5
y = 66
z = 777
print("C - '{2}' A - '{0}' B - '{1}' C again - '{2}'".format(x, y, z))

Yllä olevassa esimerkissä järjestysluvut on kirjoitettu aaltosulkeiden sisään siinä järjestyksessä, kun ne 'poimitaan' format funktion parametrilistasta. Parametrit ovat listassa järjestyksessä alkaen 0:sta, joten x on siis paikassa 0.

Muotoilua voidaan tarkentaa vielä kaksoispisteen jälkeen. Esimerkiksi:

x = 5
y = 66
z = 777
print("C - '{2:4}' A - '{0:4}' B - '{1:4}' C again - '{2:4}'".format(x, y, z))

Tässä humaamme, että kukin muuttuja tulostetaan numeroidussa järjestyksessä ja kaksoispisteen jälkeen annetaan tulostukseen varatun kentän leveys. Luku tasataan kentän oikeaan reunaan.

C - ' 777' A - '   5' B - '  66' C again - ' 777'

20.2 Merkkijonot

KAtsotaan seuraavaksi, miten merkkijonot muotoillaan.

Seuraava lista näyttää kamalalta.

my_fruit = ["Apples","Oranges","Grapes","Pears"]
my_calories = [4, 300, 70, 30]

for i in range(4):
    print(my_fruit[i], "are", my_calories[i], "calories.")

The output:

Apples are 4 calories.
Oranges are 300 calories.
Grapes are 70 calories.
Pears are 30 calories.

Muotoillaanpa sitä format komennolla. Huomaa, kuinka samalle riville voidaan tulostaa lisättyä tekstiä samalle riville.

my_fruit = ["Apples", "Oranges", "Grapes", "Pears"]
my_calories = [4, 300, 70, 30]

for i in range(4):
    print("{:7} are {:3} calories.".format(my_fruit[i],my_calories[i]) )

Tulostus on:

Apples  are   4 calories.
Oranges are 300 calories.
Grapes  are  70 calories.
Pears   are  30 calories.

Nyt tulostus näyttää kelvolliselta. Mutta, jos emme haluakaan tasata lukuja oikealle. Tässä voidaan käyttää < ja > merkkejä seuraavalla tavalla:

my_fruit = ["Apples", "Oranges", "Grapes", "Pears"]
my_calories = [4, 300, 70, 30]

for i in range(4):
    print("{:>7} are {:<3} calories.".format(my_fruit[i],my_calories[i]) )

Tulostaa:

 Apples are 4   calories.
Oranges are 300 calories.
 Grapes are 70  calories.
  Pears are 30  calories.

20.3 Alkunollat

Tämä ohjelma saa aikaan virheellisen tulostuksen:

for hours in range(1,13):
    for minutes in range(0,60):
        print("Time {}:{}".format(hours, minutes))

Ei kovin hyvin muotoiltu tulostus:

Time 8:56
Time 8:57
Time 8:58
Time 8:59
Time 9:0
Time 9:1
Time 9:2

Lisätään tulostukseen etunolla, jolloin saadaan esitettyä kellonaikoja. Kirjoittamalla pelkän 2:en sijasta kirjoitetaankin 02. Tämä täyttää kentän tyhjän merkin sijasta nollalla.

for hours in range(1,13):
    for minutes in range(0,60):
        print("Time {:02}:{:02}".format(hours, minutes))

Tulostaa:

Time 08:56
Time 08:57
Time 08:58
Time 08:59
Time 09:00
Time 09:01
Time 09:02

20.4 Liukuluvut, desimaaliluvut

Myös desimaalilukuja voidaan muotoilla. Tutki seuraavan koodina aikaan saama tulostus:

x = 0.1
y = 123.456789
print("{:.1}  {:.1}".format(x,y) )
print("{:.2}  {:.2}".format(x,y) )
print("{:.3}  {:.3}".format(x,y) )
print("{:.4}  {:.4}".format(x,y) )
print("{:.5}  {:.5}".format(x,y) )
print("{:.6}  {:.6}".format(x,y) )
print()
print("{:.1f}  {:.1f}".format(x,y) )
print("{:.2f}  {:.2f}".format(x,y) )
print("{:.3f}  {:.3f}".format(x,y) )
print("{:.4f}  {:.4f}".format(x,y) )
print("{:.5f}  {:.5f}".format(x,y) )
print("{:.6f}  {:.6f}".format(x,y) )

Ja tässä on koodin tulostus:

0.1  1e+02
0.1  1.2e+02
0.1  1.23e+02
0.1  123.5
0.1  123.46
0.1  123.457

0.1  123.5
0.10  123.46
0.100  123.457
0.1000  123.4568
0.10000  123.45679
0.100000  123.456789

Muotoilu .2 tarkoittaa lukujen esittämistä kahden numeron tarkkuudella. Valitettavasti tämä johtaa siihen, että luku 123, jossa on kolme merkitsevää numeroa, pyöristetään kahden numeron tarkkuuteen ja esitetään tieteellisessä muodossa: 1.2e+02.

Muotoilulla .2f (huomaa f) saadaan aikaiseksi tulostus kahden desimaalin tarkkudella. Joten luku 1 näytetään 1.00 ja luku 1.5555 näytetään 1.56.

Muotoilukoodiin voidaan asettaa myös kentän leveys:

x = 0.1
y = 123.456789
print("'{:10.1}'  '{:10.1}'".format(x,y) )
print("'{:10.2}'  '{:10.2}'".format(x,y) )
print("'{:10.3}'  '{:10.3}'".format(x,y) )
print("'{:10.4}'  '{:10.4}'".format(x,y) )
print("'{:10.5}'  '{:10.5}'".format(x,y) )
print("'{:10.6}'  '{:10.6}'".format(x,y) )
print()
print("'{:10.1f}'  '{:10.1f}'".format(x,y) )
print("'{:10.2f}'  '{:10.2f}'".format(x,y) )
print("'{:10.3f}'  '{:10.3f}'".format(x,y) )
print("'{:10.4f}'  '{:10.4f}'".format(x,y) )
print("'{:10.5f}'  '{:10.5f}'".format(x,y) )
print("'{:10.6f}'  '{:10.6f}'".format(x,y) )

Muotoilu 10.2f ei aseta 10 merkin leveyttä ennen desimaalipistettä ja kahta jälkeen. Se asettaa koko kentän leveydeksi 10, joten kentässä on ennen desimaalipistettä 7 merkin leveys, desimaalipiste vie yhden merkin tilan ja pisteen jälkeen tulostuu kaksi merkkiä.

'       0.1'  '     1e+02'
'       0.1'  '   1.2e+02'
'       0.1'  '  1.23e+02'
'       0.1'  '     123.5'
'       0.1'  '    123.46'
'       0.1'  '   123.457'

'       0.1'  '     123.5'
'      0.10'  '    123.46'
'     0.100'  '   123.457'
'    0.1000'  '  123.4568'
'   0.10000'  ' 123.45679'
'  0.100000'  '123.456789'

20.5 Tulostetaan valuuttasymbolit dollari ja sentti

Jos käytät tulostuksessa hintoja, niin tulosta luvut käyttäen muotoilua f. Katso esimerkki alla:

cost1  = 3.07
tax1   = cost1 * 0.06
total1 = cost1 + tax1

print("Cost:  ${0:5.2f}".format(cost1) )
print("Tax:    {0:5.2f}".format(tax1) )
print("------------")
print("Total: ${0:5.2f}".format(total1) )

Muistathan! Helposti luullaan, että %5.2f tarkoittaisi viittä numeroa, desimaalipistettä ja kahta desimaalia. Mutta näin ei sii ole. Tässä kentän koko leveys on viisi, jossa ovat mukana desimaalipiste ja numerot ennen ja jälkeen. Tulostun on:

Cost:  $ 3.07
Tax:     0.18
------------
Total: $ 3.25

Hupsis! Tässä tuleekin nyt virhe, joka on varsin yleinen hintojen kanssa toimittaessa. Huomaatko virheen? Tarkastele seuraavaa koodia alla:

cost1  = 3.07
tax1   = cost1 * 0.06
total1 = cost1 + tax1

print("Cost:  ${0:5.2f}".format(cost1) )
print("Tax:    {0:5.2f}".format(tax1) )
print("------------")
print("Total: ${0:5.2f}".format(total1) )

cost2  = 5.07
tax2   = cost2 * 0.06
total2 = cost2 + tax2

print()
print("Cost:  ${0:5.2f}".format(cost2) )
print("Tax:    {0:5.2f}".format(tax2) )
print("------------")
print("Total: ${0:5.2f}".format(total2) )


print()
grand_total = total1 + total2
print("Grand total: ${0:5.2f}".format(grand_total) )

Tulostaa:

Cost:  $ 3.07
Tax:     0.18
------------
Total: $ 3.25

Cost:  $ 5.07
Tax:     0.30
------------
Total: $ 5.37

Grand total: $ 8.63

Huomaatko virheen lukujen pyöristyksessä? Loppusumman pitäisi olla $ 8.62, mutta eipä ole.

Tulostuksen muotoilu ei pyöristä lukuja, vaan ainoastaan tulostus näkyy virheellisenä. JOs asetamme tulostukseen kolmen desimaalin tarkkuuden, niin virheen syy alkaa paljastua:

Cost:  $3.070
Tax:    0.184
------------
Total: $3.254

Cost:  $5.070
Tax:    0.304
------------
Total: $5.374

Grand total: $8.628

Nytkään muotoilu ei vaikuta luvun pyöristykseen. Käytetään tässä round funktiota luvun pyöristämiseen. KAtso alla olevaa esimerkkiä:

cost1 = 3.07
tax1 = round(cost1 * 0.06, 2)
total1 = cost1 + tax1

print("Cost:  ${0:5.2f}".format(cost1) )
print("Tax:    {0:5.2f}".format(tax1) )
print("------------")
print("Total: ${0:5.2f}".format(total1) )

cost2 = 5.07
tax2 = round(cost2 * 0.06,2)
total2 = cost2 + tax2

print()
print("Cost:  ${0:5.2f}".format(cost2) )
print("Tax:    {0:5.2f}".format(tax2) )
print("------------")
print("Total: ${0:5.2f}".format(total2) )


print()
grand_total = total1 + total2
print("Grand total: ${0:5.2f}".format(grand_total) )

Output:

Cost:  $ 3.07
Tax:     0.18
------------
Total: $ 3.25

Cost:  $ 5.07
Tax:     0.30
------------
Total: $ 5.37

Grand total: $ 8.62

round funktiolla saadaan määrättyä, mihin tarkkuuteen desimaaliluku pyöristetään. Se palauttaa pyöristetyn arvon, mutta ei vaikuta alkuperäisen luvun arvoon. Katso alla:

x = 1234.5678
print(round(x, 2))
print(round(x, 1))
print(round(x, 0))
print(round(x, -1))
print(round(x, -2))

Katso alla, miten round() funktion arvo muuttuu, kun annetaan -2 parametriksi:

1234.57
1234.6
1235.0
1230.0
1200.0

20.6 Käyttö Pygamessa

Muotoilua ei tehdä ainoastaan print-komentoja varten tekstipohjaiseen tulostukseen. Sitä voidaan käyttää esimerkiksi timer.py Pygame-ikkunassa tulostettaviin teksteihin, kuten esimerkissä kellonaikojen tulostukseen:

# Use python string formatting to format in leading zeros
output_string = "Time: {0:02}:{1:02}".format(minutes,seconds)

# Blit to the screen
text = font.render(output_string, True, BLACK)
screen.blit(text, [250, 250])

20.7 Review

20.7.1 Short Answer Worksheet

Klikkaa tästä kappaleen kertaustehtäviin.


You are not logged in. Log in here and track your progress.