-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
2411 lines (1931 loc) · 84.2 KB
/
index.html
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta name="generator" content=
"HTML Tidy for Linux (vers 25 March 2009), see www.w3.org">
<title>OKP: Python kevytspesifikaatio</title>
<meta http-equiv="content-type" content=
"text/html; charset=utf-8">
<link rel="stylesheet" href="style.css" type="text/css" media=
"screen"><!-- Syntaxhiglight -->
<script type="text/javascript" src="script/sh_main.js">
</script>
<script type="text/javascript" src="script/sh_python.js">
</script>
<link type="text/css" rel="stylesheet" href=
"script/sh_typical.css">
</head>
<body onload="sh_highlightDocument();">
<h1><img src="python_logo.png" alt="Python" id="logo" name=
"logo"> kevytspesifikaatio</h1>
<p>Kurssi: <a href=
"http://www.cs.helsinki.fi/u/wikla/OKP/K11/">581362
Ohjelmointikielten periaatteet, kevät 2011 (4 op)</a></p>
<h2>Työryhmä</h2>
<ul>
<li>Juhani Åhman <[email protected]></li>
<li>Juha Louhiranta <[email protected]></li>
<li>Matti Nauha <[email protected]></li>
<li>Timo Lehto <[email protected]></li>
</ul>
<h2>Sisältö</h2>
<ol class="toc">
<li><a href="#chapter-1">Kielen taustaa ja
miniesimerkki</a></li>
<li><a href="#chapter-2">Alkiorakenne</a></li>
<li><a href="#chapter-3">Tunnusten näkyvyysalueet</a></li>
<li><a href="#chapter-4">Kontrollin ja/tai laskennan
ohjaus</a></li>
<li><a href="#chapter-5">Perustietotyypit</a></li>
<li><a href="#chapter-6">Laskennan kapselointi</a></li>
<li><a href="#chapter-7">Datan kapselointi</a></li>
<li><a href="#chapter-8">Yhteenveto</a></li>
<li><a href="#lahteet">Lähteet</a></li>
</ol>
<h2 id="cahpter-0">Johdanto</h2>
<p>Tämä Pythonin kevytspesifikaatio on toteutettu keväällä 2011 osana Helsingin
yliopiston tietojenkäsittelytieteen laitoksen Ohjelmointikielten periaatteet
-kurssia. Tämän työn tarkoituksena on antaa yleiskatsaus Python-kielen
ominaisuuksista. Dokumentaatiomme koskee ensisijaisesti Pythonin 3.x-kehityshaaraa,
mutta suurin osa pätee myös vanhempiinkin versioihin.</p>
<h2 id="chapter-1">1. Kielen taustaa ja miniesimerkki</h2>
<p>Tässä luvussa käsittelemme hieman kielen taustaa ja sen syntyä. Käymme lyhyesti läpi sen ominaisuuksia ja mahdollisia käyttökohteita. Lopuksi näytämme Pythonilla toteutetun Fibonaccin lukujonoa koskevan esimerkin.</p>
<ol class="sub-toc">
<li><span>1.1.</span><a href="#chapter-1-historia">Historia</a></li>
<li><span>1.2.</span><a href="#chapter-1-perustietoa">Python
perustietoa</a></li>
<li><span>1.3.</span><a href="#chapter-1-kayttokohteet">Käyttökohteet</a></li>
<li><span>1.4.</span><a href="#chapter-1-fibonacci">Fibonacci esimerkki</a></li>
</ol>
<h3 id="chapter-1-historia">1.1. Historia</h3>
<p>Pythonin historia alkaa 1980-luvulta. Ensimmäinen versio
ohjelmointikielestä kehitettiin 80-luvun loppupuolella Guido van
Rossumin toimesta. Python kehitettiin ABC kielen seuraajaksi,
joka kykenee mm. poikkeusten käsittelyyn ja yhteistyöhön Amoeba-käyttöjärjestelmän kanssa. Kielen alun perin kehittänyt van
Rossum on edelleen aktiivisesti mukana kielen kehittämisessä</p>
<p>Python 2.0, julkaistiin 16. lokakuuta 2000. Toinen versio
sisälsi useita uusia ominaisuuksia, mukaan lukien täydellisen
roskienkeruumekanismin ja Unicode-tuen. Muutos tapahtui myös
kielen kehitysprosessissa. Python-yhteisölle annettiin vapaammat
kädet osallistua mukaan kielen kehitykseen.</p>
<p>Joulukuussa 2008 ilmestyi 3.0, jolla haluttiin korjata
havaittuja ongelmia kielessä. Kielestä haluttiin poistaa
duplikaatteja ominaisuuksia poistamalla vanhat tavat tehdä
asioita. 3.x ei ole taaksepäin yhteensopiva versioiden 2.x ja
vanhempien kanssa. Vanhoille versioille kirjoitetut ohjelmat
eivät toimi suoraan versiossa 3.0. Siirtymän helpottamiseksi on
toteutettu käännösohjelma (<code>2to3</code>), joka kääntää
automaattisesti osan koodista kielen uudempaan versioon. Lisäksi
useita kolmosversion keskeisiä ominaisuuksia on toteutettu
rinnakkain kehitettyyn 2.6 versioon, mikä mahdollistaa niiden
hyödyntämisen ilman uudempaan syntaksiin siirtymistä. [<a href=
"#ref-history-of-python">3</a>]</p>
<h3 id="chapter-1-perustietoa">1.2. Python perustietoa</h3>
<ul>
<li>Keskeinen suunnittelufilosofia: selkeä, luettava
syntaksi</li>
<li>Tulkattava</li>
<li>Oliosuuntautunut ohjelmointikieli</li>
<li>Korkean tason dynaamiset datatyypit</li>
<li>Kattavat standardikirjastot ja saatavilla paljon kolmansien
osapuolien moduuleja eri tarkoituksiin</li>
<li>Poikkeuksiin <i>(exception)</i> pohjautuva virheiden
hallinta</li>
<li>Tukee useita ohjelmointiparadigmoja <i>(esim.
oliopohjainen, proseduraalinen, funktionaalinen)</i></li>
<li>Toimii useilla eri alustoilla, esim.
<ul>
<li>Windows</li>
<li>Mac</li>
<li>Linux</li>
<li>Amiga</li>
<li>Nokia series 60</li>
</ul>
</li>
<li>Avoin lähdekoodi, vapaasti käytettävissä ja jaettavissa
(myös kaupalliseen käyttöön)</li>
<li>Upotettavissa sovelluksiin skriptausrajapintana <i>(esim.
Blender)</i></li>
<li>Käytössä myös muun muassa <a href=
"http://www.djangoproject.com/">Django</a>-frameworkissa.</li>
<li>Python nimi tulee tv-sarjasta <i>Monty Python's Flying
Circus</i>.</li>
</ul>
<p>Pythonista on tällä hetkellä olemassa kaksi vakaata haaraa.
2.x-haara saa tällä hetkellä pelkkiä virheitä korjaavia
päivityksiä. Uudet ominaisuudet kehitetään vain 3.x-haaralle.
Suurempi osa kolmansien osapuolien ohjelmistoista käyttää vielä
Pythonin 2.x-versiota.</p>
<p>Yleisin Pythonin toteutus on CPython, joka on kirjoitettu
C-kielellä. CPython kääntää Python ohjelmat. Se kääntää Python
ohjelmat tavukoodiksi, joka suoritetaan virtuaalikoneessa.
CPython on saatavilla useille eri käyttöjärjestelmille ja sen
mukana tulee laaja peruskirjasto.</p>
<p>Muita Python toteutuksia on esimerkiksi <a href=
"http://www.jython.org/">Jython</a> (JVM), <a href=
"http://ironpython.net/">IronPython</a> (.NET) ja <a href=
"http://pypy.org/">PyPy</a> (Python).</p>
<h3 id="chapter-1-kayttokohteet">1.3. Käyttökohteet</h3>
<p>Yksi suosittu tapa hyödyntää Pythonia on sen käyttäminen
skriptikielenä erilaisissa sovelluksissa. Pythonia käyttävät
skriptikielenä esimerkiksi 3d-mallinnusohjelmistot Maya ja
Blender, kuvankäsittelyohjelma GIMP ja se on toinen valittavissa
oleva skriptikieli Google Docsissa</p>
<p>Erilaisten kirjastojen, muun muassa NumPy, SciPy, Matplotlib
avulla Pythonia voidaan käyttää tehokkaasti tieteelliseen
laskentaan.</p>
<p>Monissa käyttöjärjestelmissä Python kuuluu
peruskomponentteihin. Python löytyy muun muassa useimmista Linux
distribuutioista, OpenBSD:stä ja Mac OS X:stä.</p>
<h3 id="chapter-1-fibonacci">1.4. Fibonacci esimerkki</h3>
<p>Seuraavassa esimerkki ohjelmasta, joka lukee yhden
syöttöluvun, laskee ensimmäisen Fibonaccin luvun, joka on
syöttölukua suurempi ja lopuksi tulostaa kyseisen Fibonaccin
luvun.</p>
<pre class="sh_python">
import sys
def fib(n):
"""Palauttaa ensimmäisen Fibonaccin luvun, joka on syöttölukua suurempi."""
a, b = 0, 1
while b <= n:
a, b = b, a+b
return b
if __name__ == "__main__": # Pääohjelma
s = input("Anna fibonacci syöttöluku: ") # Lue syöte käyttäjältä
# input palauttaa aina stringin, mutta haluamme kokonaisluvun
try:
# Yritä muuttaa syöte kokonaislukutyypiksi
n = int(s)
except ValueError:
# Tyypin muutos epäonnistui, poistu ohjelmasta virheviestillä
sys.exit("Antamasi syöte ei ollut kokonaisluku!")
print(fib(n))
</pre>
<p>Ensimmäisen rivin <code>import sys</code> lause importtaa eli
tuo fibonacci-moduulin sys-moduulin käytettäväksi. sys-moduulin
exit-metodia käytetään ohjelman loppupuolella päättämään ohjelman
suoritus sopivalla virheviestillä, jos käyttäjän antama syöte ei
ollut kokonaisluku.</p>
<p>Varsinainen Fibonacci luvun laskeminen tapahtuu
<code>fib</code>-funktiossa. <code>fib</code>-funktio asettaa ensiksi muuttujille a ja b
Fibonaccin lukujonon alkuarvot <code>a = 0</code> ja <code>b =
1</code>. Lukujonon lukuja lasketaan <code>while</code>-silmukassa, kunnes
viimeisin laskettu Fibonaccin luku <code>b = a+b</code> on
syöttölukua suurempi. Lopuksi palautamme halutun luvun.</p>
<p>Koska Python ohjelmissa ei ole varsinaista
"pääohjelmafunktiota", niin se yleensä merkitään näkyviin
<code>if __name__ == "__main__":</code> lauseella. Tämä suorittaa
pääohjelma-alueen vain kun moduuli suoritetaan pääohjelmana eikä
importattuna jostain toisesta moduulista.</p>
<p>Käyttäjän syöte luetaan <code>input</code>-funktiolla. <code>fib</code>-funktiota varten
halutaan kokonaislukusyöte. Syötteen tyyppi on riippuvainen
käyttäjästä, joten se muutetaan kokonaisluvuksi ennen
fib-funktion kutsua <code>int(x)</code>-kutsulla.
Kokonaislukumuutos voi kuitenkin epäonnistua, jolloin
<code>int(x)</code> nostaa <code>ValueError</code> poikkeuksen.
Jotta käyttäjälle saadaan annettua sopiva virheviesti, niin
käsittelemme poikkeuksen <code>try</code>-<code>except</code>-rakenteen avulla. Pääohjelman
lopuksi kutsumme <code>fib</code>-funktiota syötteellä ja tulostamme sen
palautusarvon.</p>
<h2 id="chapter-2">2. Alkiorakenne</h2>
<p>Tässä luvussa käymme läpi millaisista osista ohjelmat rakennetaan. Kerromme
muutamista syntaksii liittyvistä seikoista kuten mm. omien tunnusten luontiin
liittyvät säännöt, listan varatuista sanoista.</p>
<ol class="sub-toc">
<li><span>2.1.</span><a href="#chapter-2-tunnukset">Tunnukset</a></li>
<li><span>2.2.</span><a href="#chapter-2-varatut-sanat">Varatut sanat,
avainsanat</a></li>
<li><span>2.3.</span><a href=
"#chapter-2-literaalivakiot">Literaalivakiot</a></li>
<li><span>2.4.</span><a href="#chapter-2-erottimet-yms">Erottimet, sisennykset,
rivinvaihdot</a></li>
<li><span>2.5.</span><a href="#chapter-2-edut-ja-haitat">Arvio kieleen
valittujen ratkaisujen eduista ja haitoista</a></li>
</ol>
<h3 id="chapter-2-tunnukset">2.1. Tunnukset</h3>
<p>Python 3:ssa tunnukset voidaan nimetä käyttäen merkkejä a-z,
A-Z, 0-9 ja _. Tunnus ei kuitenkaan voi alkaa numerolla. Pienet
ja iso kirjaimet tulkitaan eri kirjaimiksi. Tunnukset voivat olla
rajoittamattoman pituisia. Lisäksi Python 3 tukee suurta joukkoa
ASCII-järjestelmän ulkopuolisia unicode-merkkejä. Tarkempi
listaus tuetuista merkeistä löytyy osoitteesta: <a href=
"http://www.dcl.hpi.uni-potsdam.de/home/loewis/table-3131.html">http://www.dcl.hpi.uni-potsdam.de/home/loewis/table-3131.html</a>.
Merkit on jaoteltu kahteen osaan: ID_Start ja ID_Continue,
excluding ID_Start. Näiden merkkijoukkojen yhdiste sisältää
kaikki unicode-merkit joita voi esiintyä python-tunnuksen
nimessä, siten että tunnuksen nimi voi alkaa vain ensimmäisen
joukon merkillä. <a href="#ref-tunnukset-py3-spec">[2]</a></p>
<p>Seuraavassa lyhyt esimerkki joka demonstroi erikoisempien
merkkien käyttöä Python 3 ohjelmassa:</p>
<pre class="sh_python">
#!/usr/bin/python3.1
# -*- coding: UTF-8 -*-
def python_3_tukee_unicodemerkkejä_varsin_laajasti(ភាសាខ្មែរ="khemrin kieli khmeriksi"):
print("Hei vaan ja hellurei!", ភាសាខ្មែរ)
epävalidia_python_koodia='kuitenkin_esim_€_merkki_ei_ole_sallittu = "epic fai"'
try:
exec(epävalidia_python_koodia)
except SyntaxError as se:
print("€-merkki ei ollut sallittu muuttujan nimessä :'(", se)
validia_python_koodia = epävalidia_python_koodia.replace("€", "e")
exec(validia_python_koodia)
print("Hyvin pyyhkii. No problemo, kun €-merkit vaihdettiin e-kirjaimiksi")
if __name__ == "__main__":
python_3_tukee_unicodemerkkejä_varsin_laajasti()
</pre>
<p>Yllä oleva python ohjelma tulostaa konsoliin tekstin:</p>
<pre>
Hei vaan ja hellurei! khmerin kieli khmeriksi
€-merkki ei ollut sallittu muuttujan nimessä :'( invalid character in identifier (<string>, line 1)
Hyvin pyyhkii. No problemo, kun €-merkit vaihdettiin e-kirjaimiksi
</pre>
<p><a href="esimerkit/unicode_sample.py">Lataa esimerkki
tästä</a></p>
<h3 id="chapter-2-varatut-sanat">2.2. Varatut sanat</h3>
<p>Seuraavassa listattuna (Python 3.0.1:n mukainen, tässä on
pieniä eroavaisuuksia 2.x-sarjan kanssa) varatut sanat <a href=
"#ref-varatut-sanat-py3-spec">[1]</a> sen tarkemmin niitä
esittelemättä.</p>
<pre>
False class finally is return
None continue for lambda try
True def from nonlocal while
and del global not with
as elif if or yield
assert else import pass
break except in raise
</pre>
<h3 id="chapter-2-literaalivakiot">2.3. Literaalivakiot</h3>
<p>Python tukee seuraavia literaalivakioita [<a href=
"#ref-literaalivakiot">4</a>]:</p>
<ul>
<li>merkkijonot,<br>
<code>"hello"</code>, <code>'world'</code>,<br>
<code>"""Olen<br>
monella<br>
rivillä"""</code></li>
<li>kokonaisluvut,<br>
<code>7</code>, <code>79228162514264337593543950336</code>,
<code>0b100110111</code>, <code>0xdeadbeef</code></li>
<li>liukuluvut,<br>
<code>3.14</code>, <code>10.</code>, <code>.001</code>,
<code>1e100</code>, <code>3.14e-10</code>,
<code>0e0</code></li>
<li>imaginaariluvut<br>
<code>3.14j</code>, <code>10.j</code>, <code>10j</code>,
<code>.001j</code>, <code>1e100j</code>,
<code>3.14e-10j</code></li>
</ul>
<p>Numeerisista literaaleista on hyvä mainita vielä se, että ne
eivät sisällä etumerkkiä. Esimerkiksi merkintä <code>-1</code>
koostuu yksipaikkaisesta operaatiosta <code>-</code> ja
literaalista <code>1</code>.</p>
<h3 id="chapter-2-erottimet-yms">2.4. Erottimet, sisennykset,
rivinvaihdot</h3>
<p>Pythonissa käytetään sisennyksiä rajaamaan lohkoja. Sisennystä
kasvatetaan tiettyjen lausekkeiden jälkeen ja vastaavasti
sisennystä pienennetään lohkon päättymisen merkiksi. Sekä
tabulaattorit että välilyönnit kelpaavat sisennysmerkeiksi
Pythonissa.</p>
<p>Sisennyksen määrällä ei ole väliä, sisennys voi olla yhden
tabulaattorin tai vaikkapa kuuden välilyönnin pituinen
<i>(<b>huom!</b> tabulaattorin ja välilyöntien sekaisin
käyttäminen ei ole sallittua Pythonissa)</i>. Ainoastaan
suhteellisella sisennyksen määrällä on väliä sisäkkäisissä
lohkoissa.</p>
<p>Lauseet erotellaan toisistaan rivinvaihdoilla. Useita lauseita
voidaan kirjoittaa samalle riville käyttämällä puolipistettä.
Kontrollirakenteissa totuusarvolausekkeita seuraa aina
kaksoispiste ja lausekkeessa ei ole pakko käyttää sulkuja.</p>
<p>Alla olevissa esimerkeissä kaikki kolme <code>if</code>-rakennetta tekevät
saman asian <i>(tulostavat sanat "spam" ja "ham")</i>:</p>
<pre class="sh_python">
if 1 == 1:
print("spam")
print("ham")
</pre>
<pre class="sh_python">
if 1 == 1:
print("spam"); print("ham")
</pre>
<pre class="sh_python">
if 1 == 1: print("spam"); print("ham")
</pre>
<h3 id="chapter-2-edut-ja-haitat">2.5. Arvio kieleen valittujen
ratkaisujen eduista ja haitoista</h3>
<p>Unicode-tuki Python 3:ssa tekee aidosti mahdolliseksi
ohjelmoinnin ohjelmoijan omalla äidinkielellä. Tämä on varmasti
monessa mielessä hyvä asia ja sen hyödyntäminen todennäköisesti
parantaa koodin luettavuutta kehittäjäyhteisössä. Toisaalta tällä
alalla ei ole ollenkaan tavatonta, että ohjelmaa kehitetään
ympäri maailmaa ja kehittäjien äidinkielet vaihtelevat suuresti.
Tällöin on käytettävä jotakin yhteistä kieltä eli siis yleensä
englantia ja tämä unicode-tuki ei juurikaan auta. Toinen tilanne
jolloin koodia ei varmaankaan haluta tehdä äidinkielellä on, jos
tuotetaan avoimen lähdekoodin ratkaisuja. Muutoin saatetaan
varsin tehokkaasti eliminoida iso osa käyttäjäyhteisön
potentiaalista jatkokehittää tuotetta. Yleisesti ottaen tuote
joka on ohjelmoitu vaikkapa suomeksi rajoittaa
jatkokehitysmahdollisuuksia vaikka alkuperäisen kehitystyön
kannalta kielivalinnalla olisikin ollut positiivisia vaikutuksia.
Kustannussyistä jatkokehitys saatettaisiin joissain tilanteissa
haluta tuottaa jossakin edullisemmassa maassa, mutta tämä ei nyt
olekaan mahdollista ilman huomattavaa käännöstyötä. Kun lisäksi
otetaan huomioon, että unicode-tuen sisällyttäminen tunnuksiin
monimutkaistaa kielen implementaatioiden toteuttamista, niin olen
kyllä henkilökohtaisesti hieman skeptinen koko ominaisuuden
järkevyydestä. En kyllä itse ainakaan ikinä ohjelmoisi
vakavissani mitään millään muulla kielellä kuin englannilla.</p>
<p>Pythonissa sisennystapa ei ole ohjelmoijan täysin vapaasti
valittavissa, vaan ohjelmoinnissa pakotetaan käyttämään
tietynlaista sisennystyyliä. Etu tästä on, että ohjelmoija ei voi
vahingossa kirjoittaa sekavasti sisennettyä koodia, koska se
rikkoo ohjelman suorituksen. Virheiden mahdollisuus pienenee, kun
ohjelma tekee, mitä se näyttääkin tekevän, kun virheellinen
sisentäminen ei pääse sekoittamaan lukijaa. Python koodin
luettavuutta parantaa se, että kaikki joutuvat käyttämään
yhtenäistä sisennystapaa.</p>
<h2 id="chapter-3">3. Tunnusten näkyvyysalueet</h2>
<!-- TODO: parempi ryhmittely ja otsikkojen nimet -->
<p>Tässä luvussa kerromme miten ja missä itse määritellyt rakenteet ovat käytettävissä.</p>
<ol class="sub-toc">
<li><span>3.1.</span><a href="#chapter-3-lohkorakenne">Lohkorakenne</a></li>
<li><span>3.2.</span><a href="#chapter-3-sidonta">Sidonta</a></li>
<li><span>3.3,</span><a href=
"#chapter-3-sidonta-esim">Esimerkki tunnusten näkyvyydestä, lohkorakenteista ja
sidonnasta</a></li>
<li><span>3.4.</span><a href=
"#chapter-3-sisakkaiset-nimiavaruudet-ja-funktiot">Sisäkkäiset
nimiavaruudet ja funktiot</a></li>
<li><span>3.5.</span><a href="#chapter-3-1-2-ja-3-luokan-arvo">Ensimmäisen,
toisen ja kolmannen luokan arvo</a></li>
<li><span>3.6.</span><a href="#chapter-3-edut-ja-haitat">Arvio kieleen
valittujen ratkaisujen eduista ja haitoista</a></li>
</ol>
<h3 id="chapter-3-lohkorakenne">3.1. Lohkorakenne</h3>
<p>Pythonissa lohkoksi kutsutaan koodinpätkää, joka suoritetaan
yhtenä yksikkönä. Seuraavia rakenteita kutsutaan lohkoiksi: [<a href="#ref-nimet-ja_sidonta-py3-spec">6</a>]</p>
<ul>
<li>moduuli</li>
<li>funktion vartalo</li>
<li>luokan määrittely</li>
<li>jokainen interaktiivisesti kirjoitettu komento</li>
<li>skriptitiedosto (annettuna tulkille
komentoriviparametrina)</li>
<li>skriptikomento (annettuna tulkille <code>-c</code> komentoriviparametrin
arvona)</li>
<li><code>exec</code>- tai <code>eval</code>-funktioille merkkijonona annettu
koodi</li>
</ul>
<p>Kuten on jo aiemmin mainittu Python käyttää sisennyksiä
määrittelemään lohkoja. Sisennys kasvaa tiettyjen ilmaisujen
jälkeen ja puolestaan pienenee lohkon loppumisen merkiksi.
Samalla tasolla lohkossa sijaitsevat lauseet kirjoitetaan
jokainen omalle riville käyttäen samaa sisennystä (tai tietenkin
vaihtoehtoisesti kirjoittamalla kaikki samalle riville käyttäen
<code>;</code>-merkkiä erottimena).</p>
<p>Lohkon määrittely voidaan aloittaa mm. seuraavilla sanoilla:
<code>if, else, elif, for, while, try, except, finally, class,
def, with, pass</code>.</p>
<p>Jos lohkon sisällä määritellään lokaali muuttuja, on tämän
muuttujan näkyvyysalue (scope) rajoitettu siihen lohkoon. Mikäli
tunnus määritellään funktion vartalossa, niin näkyy se myös
funktion vartalon sisäisille lohkoille (elleivät nämä sido
tunnukselle uutta merkitystä). Moduulitason tunnukset ovat
globaaleja. Mikäli lohkon sisältä halutaan (eksplisiittisesti)
viitata lohkon ulkopuolisiin muuttujiin, niin voidaan käyttää
varattuja sanoja <code>nonlocal</code> ja <code>global</code>. Määreellä <code>nonlocal</code>
vihjataan, että halutaan viitata näkyvyysaluehierarkiassa
seuraavaan tasoon jolta tunnus löytyy. Vastaavasti
<code>global</code>-määreellä siirrytään suoraan etsimään tunnusta globaalilta
näkyvyysalueelta.</p>
<h3 id="chapter-3-sidonta">3.2. Sidonta</h3>
<p>Pythonissa sidonta tapahtuu osittain dynaamisesti ja osittain
staattisesti. Käytännössä siis näkyvyysalueet (<em>scope</em>)
määritellään staattisesti, mutta niitä käytetään dynaamisesti.
Eli toisin sanoen eri näkyvyysalueilla olevat tunnukset
määritellään, mutta niihin ei liitetä arvoa. Ajonaikaisesti
voidaan määritellä uusia tunnuksia globaalille tasolle. On
kuitenkin huomioitava, että Python-funktioille ei voi määritellä
uusia lokaaleja tunnuksia funktion parsimisen jälkeen (eli
lokaalit muuttujat määritellään staattisesti). Pythonin
dokumentaatioissa [<a href="#ref-scopes-and-namespaces">30</a>] myös vihjataan, että staattisuutta tullaan
jatkossa lisäämään (ja näin ollen dynaamiseen sidontaan
nojautumista kehotetaan välttämään).</p>
<h3 id="chapter-3-sidonta-esim">3.3 Esimerkki tunnusten näkyvyydestä, lohkorakenteista ja
sidonnasta</h3>
<p>Seuraava esimerkki pyrkii demonstroimaan hieman kaikkea
tunnusten näkyvyyteen liittyvää. Siinä näytetään miten saadaan
aikaan ajonaikainen poikkeus sidonnasta ja toisaalta myös
demonstroidaan muuttujien näkyvyyttä.</p>
<pre class="sh_python">
#!/usr/bin/python3.1
# -*- coding: UTF-8 -*-
muuttuja="globaali"
print("moduulitasolla", muuttuja)
def main():
import sys
#muuttuja on selvästi edelleen globaalien nimien joukossa
if 'muuttuja' in globals(): print("muuttuja on määritelty globaalilla tasolla")
try:
#FAIL! UnboundLocalError: local variable 'muuttuja' referenced before assignmen!
print("fail", muuttuja)
except UnboundLocalError:
name, msg = sys.exc_info()[:2]
#Btw. alemmalla lohkotasolla määritellyt muuttujat näkyvät ylemmälle
print(name.__name__+":", msg)
#Ja syy on seuraavalla koodirivillä. Näin käy sillä kääntäjä merkitsee seuraavan
#lauseen takia nimen muuttuja olemaan tyypiltään lokaali viittaus tässä
#lohkossa. Siten suoritusaikana kun nimeen muuttuja viitataan yllä, sitä
#etsitäänkin vain lokaalien muuttujien joukosta. Koska tämä lause jossa lokaali
#nimi muuttuja sidotaan merkkijonoon "lokaali", on ensimmäisen nimeen tehdyn
#viittauksen jälkeen tässä lohkossa, on muuttuja tässä siis vielä
#sitomatta.
muuttuja = "lokaali"
print("main", muuttuja)
def fun():
global muuttuja
print("funktio", muuttuja)
fun()
lam = lambda: print("lambda", muuttuja)
lam()
#Seuraava if-rakenne saisi kuitenkin aikaan sen, että kaikkialla main-metodissa
#tunnus muuttuja viittaisi saman nimiseen moduulitason globaaliin muuttujaan.
#Tämä ei toki sinänsä liene kovin yllättävää, mutta toimii kuitenkin pienenä
#demonstraatio siitä, että if-rakenne ei ole lohko. Ei ainakaan Pythonissa :)
#if True:
# global muuttuja
# print("globaali", muuttuja)
if __name__ == '__main__':
main()
print("moduulitasolla if-lohkossa", muuttuja)
</pre>
<p>Skripti tekee seuraavan tulostuksen (<a href=
"esimerkit/unbound_excep_esim.py">lataa esimerkki</a>)</p>
<pre>
moduulitasolla globaali
muuttuja on määritelty globaalilla tasolla
UnboundLocalError: local variable 'muuttuja' referenced before assignment
main lokaali
funktio globaali
lambda lokaali
moduulitasolla if-rakenteessa globaali
</pre>
<h3 id="chapter-3-sisakkaiset-nimiavaruudet-ja-funktiot">
3.4 Sisäkkäiset nimiavaruudet ja funktiot</h3>
<p>Python tukee sisäkkäisiä nimiavaruuksia versiosta 2.2 lähtien
[<a href="#ref-sulkeumat-py22">5</a>]. Sitä ennen nimiavaruuksia
oli vain kolme: paikallinen nimiavaruus, moduulitason nimiavaruus
ja sisäänrakennettu nimiavaruus. Vaikka funktion määrittely oli
mahdollista toisen funktion sisällä, niin sisäkkäinen funktio ei
voinut viitata oman nimiavaruutensa ulkopuolisiin nimiin.</p>
<pre class="sh_python">
def eka(p):
x = "olen ekan x"
print("--- eka alkaa ---")
p() # tokan paikalliset eivät näy tänne.
# funktio p käydään suorittamassa määrittelykohdan ympäristössä
print(x)
print("--- eka päättyy ---")
def toka():
print("--- toka alkaa ---")
x = "olen tokan x"
def fpar():
nonlocal x # muuttuja x viittaa nyt sulkeuman ulkopuoliseen viimeiseksi
# sidottuun tunnukseen eli tokan muuttujaan x
print(x)
x = "tokan x on muutettu!"
eka(fpar) # "nimetyn sulkeuman" välitys funktioparametrina
print(x) # viittaus paikalliseen tunnukseen
print("--- toka päättyy ---")
if __name__ == "__main__": # Pääohjelma
toka()
</pre>
<p>Ohjelma tulostaa:</p>
<pre>
--- toka alkaa ---
--- eka alkaa ---
olen tokan x
olen ekan x
--- eka päättyy ---
tokan x on muutettu!
--- toka päättyy ---
</pre>
<p>Python tukee myös anonyymejä funktioita lambda-lausekkeiden
muodossa. Lambda-lausekkeella voi helposti luoda pieniä
anonyymejä funktioita. Esimerkiksi funktio <code>lambda: a, b:
a*b</code> palauttaa kahden argumenttinsa kertolaskun.
Lambda-lauseke on kuitenkin aina vain yksi lauseke eikä lause,
joten siihen ei voi sisällyttää esimerkiksi toisto- tai
ehtolauseita suoraan. Se ei siis vastaa useimpien muiden kielten
anonyymejä funktioita. Lambda-lausekkeet voivat viitata
nimiavaruutensa ulkopuolisiin tunnuksiin kuten funktiot:</p>
<pre class="sh_python">
def tee_kertoja(n):
return lambda x: x * n
f = tee_kertoja(5)
print(f(3)) # 15
print(f(5)) # 25
</pre>
<h3 id="chapter-3-1-2-ja-3-luokan-arvo">3.5. Ensimmäisen, toisen ja
kolmannen luokan arvo</h3>
<p>Pythonissa yksi tavoitteista on ollut tehdä kaikista
objekteista ensimmäisen luokan arvoja, eli sellaisia, joita
voidaan:</p>
<ul>
<li>sijoittaa muuttujaan</li>
<li>välittää parametrina</li>
<li>palauttaa funktion arvona</li>
</ul>
<p>Huomion arvoista on, että Pythonissa myös metodit ovat
ensimmäisen luokan arvoja. [<a href=
"#ref-ensimmaisenluokan">7</a>]</p>
<h3 id="chapter-3-edut-ja-haitat">3.6. Arvio kieleen valittujen
ratkaisujen eduista ja haitoista</h3>
<p>Lohkojen pakotettu sisentäminen on hyvä asia, koodin
luettavuus lisääntyy ja se myös pakottaa kaikki kirjoittamaan
koodia samalla tavalla eli sisentäen.</p>
<h2 id="chapter-4">4. Kontrollin ja/tai laskennan ohjaus</h2>
<p>Tässä luvussa kerromme miten perustoiminnallisuudet ilmaistaan. Esittelemme millaisia mahdollisuuksia Pythonissa on valintaan, iteraatioon ja rekursioon liittyvissä asioissa.</p>
<ol class="sub-toc">
<li><span>4.1.</span><a href="#chapter-4-valinta">Valinta</a></li>
<li><span>4.2.</span><a href="#chapter-4-toisto">Toisto eli iteraatio</a></li>
<li><span>4.3.</span><a href="#chapter-4-rekursio">Rekursio</a></li>
<li><span>4.4.</span><a href="#chapter-4-arvio">Arvio kieleen valittujen
ratkaisujen eduista ja haitoista</a></li>
</ol>
<h3 id="chapter-4-valinta">4.1. Valinta</h3>
<h4>4.1.1. <code>if</code>-lause</h4>
<p><code>if</code>-lause koostuu kolmesta eri osasta
<code>if</code>, <code>elif</code>, <code>else</code>.</p>
<pre class="sh_python">
x = int(input("Please enter an integer: "))
if x < 0:
x = 0
print('Negative changed to zero')
elif x == 0:
print('Zero')
elif x == 1:
print('Single')
else:
print('More')
</pre>
<p>Edellinen koodi tuottaa esimerkiksi seuraavanlaisen tulosteen:</p>
<pre>
Please enter an integer: <strong>42</strong>
More
</pre>
<p><code>elif</code>-osioita voi yhdessä lauseessa olla
mielivaltainen määrä tai ei yhtään. Myös <code>else</code>-osan
käyttö on vapaaehtoista. Python ei tue monista muista kielistä
tuttua switch-case-rakennetta vaan tämä tulee toteuttaa
if-rakenneella [<a href="#ref-controlflow">8</a>].</p>
<h3 id="chapter-4-toisto">4.2. Toisto eli iteraatio</h3>
<p>Monista kielistä poiketen toistolausekkeilla on Pythonissa else-lause [<a href=
"#ref-controlflow">8</a>], joka suoritetaan jos <code>for</code>-lauseessa
lista loppuu tai jos <code>while</code>-lause saa
arvon <code>False</code>. <code>else</code>-lohkoa ei suoriteta
jos toistolauseesta poistutaan <code>break</code>-lauseella.</p>
<h4>4.2.1. <code>for</code>-lause</h4>
<p><code>for</code>-lausetta käytetään iterointiin. Lause käyttää hyväkseen
annetun objektin iteraattoria, jota se käy järjestyksessä läpi
kunnes viimeinen arvo on saavutettu. Muista kielistä poiketen
tässä rakenteessa ei voi erikseen määritellä iteraatioaskelta tai
pysäytysehtoa.</p>
<pre class="sh_python">
a = ['cat', 'window', 'defenestrate']
for x in a:
print(x, len(x))
</pre>
<p>Edellinen koodi tulostaa:</p>
<pre>
cat 3
window 6
defenestrate 12
</pre>Seuraavassa <code>for</code>-lauseessa puretaan listassa
olevat monikot ja käytetään <code>string</code>-luokasta löytyvää
korvausoperaatiota, joka muuttaa <code>{}</code>-merkkien välistä
löytyvä kohdat halutuiksi.
<pre class="sh_python">
animals = [ ('Cat', 'Meow'),
('Cow', 'Moo'),
('Dog', 'Woof')]
for animal, sound in animals:
print("{0} says {1}!".format(animal, sound))
</pre>
<p>Edellinen koodi tulostaa:</p>
<pre>
Cat says Meow!
Cow says Moo!
Dog says Woof!
</pre>
<p>Haluttaessa toistaa tietty koodi useampaan kertaan voidaan
käyttää hyväksi esimerkiksi <code>range</code>-funktiota, joka
tuottaa halutun kokoisen kokonaislukuiteraattorin.</p>
<pre class="sh_python">
for i in range(5):
print(i)
</pre>
<p>Edellinen koodi tulostaa:</p>
<pre>
0
1
2
3
4
</pre>
<h4>4.2.2. <code>while</code>-lause</h4>
<p><code>while</code>-lausetta käytetään suorittamaan lauseessa
olevaa koodia niin pitkään kun jatkamisehto pysyy totena
[<a href="#ref-compoundstatement">9</a>]. Pythonissa ei ole
erillistä loppuehtoista do-while-lausetta. Sama tulos voidaan
kuitenkin saavuttaa muotoilemalla <code>while</code>-lause
oikein (esim. <code>while True:</code> ja sisällä tarkistus
<code>if condition: break</code>)</p>
<pre class="sh_python">
x = 3
while x < 3:
print("Loopissa")
x += 1
else:
print("Loopin else")
</pre>
<p>Edellinen koodi tulostaa:</p>
<pre>
Loopissa
Loopissa
Loopissa
Loopin else
</pre>
<h4>4.2.3. <code>continue</code> & <code>break</code>-lauseet</h4>
<p><code>continue</code>-lause hyppää toistorakenteessa suoraan
toistorakenteen seuraavalle iteraatiokierrokselle. Tätä voidaan
käyttää siis, kun halutaan ohittaa osa toistorakenteen koodista
juuri tällä suorituskerralla. <code>break</code>-lause lopettaa
toistorakenteen suorittamisen ilman ns. pysäytysehdon täyttymistä
[<a href="#ref-compoundstatement">9</a>].</p>
<h3 id="chapter-4-rekursio">4.3. Rekursio</h3>
<p>Rekursiivisissa ohjelmarutiineissa idea on sama kuin
matemaattisesti määritellyissä rekursiivisissa funktioissa, ja
rekursiivisesti lasketut välitulokset tallennetaan useimmiten
pinoon. Viimeisellä rekursiokierroksella pinosta kerätään
vastaukset käänteisessä järjestyksessä. Python tukee rekursiota
eli sallii funktion kutsua itse itseään.</p>
<p>Python ei tee eroa normaalin rekursion tai häntärekursion
välillä [<a href="#ref-tail-recursion">11</a>]. Toisin sanoen se
ei siis toteuta ominaisuuksia (tunnetaan mm. nimillä <em>tail
call elimination</em> tai <em>tail call optimization</em>),
joilla voitaisiin optimoida tilankäyttöä tallettamalla
häntärekursiossa kutsuttavan funktion aktivaatiotietue kutsujan
aktivaatiotietueen tilalle pinoon eli muuntamalla rekursio
vastaamaan tavallista silmukkaa.</p>
<p>Rekursion syvyys on rajoitettu Pythonissa. Tyypillisessä
Pythonin implementaatiossa raja-arvo on 1000. Raja estää ikuista
silmukkaa aiheuttamasta ylivuotoa C:n pinossa ja kaatamasta
Pythonia [<a href="#ref-library-sys">10</a>]. <code>sys</code>-moduulista
löytyvät mekanismit, joilla voidaan selvittää
maksimaalinen rekursiosyvyys
(<code>sys.getrecursionlimit()</code>) tai asettaa se
(<code>sys.setrecursionlimit(int)</code>). Rekursiosyvyyden
oletusarvo riippuu implementaatiosta, kun taas suurin mahdollinen
arvo on laitteistoriippuvainen.</p>
<p>Fibonaccin luvun laskeminen rekursiivisesti. Laskee luvun,
jonka järjestys on n.</p>
<pre class="sh_python">
def fib(n):
if n == 0:
return 0
elif n == 1:
return 1
else:
return fib(n-1) + fib(n-2)
</pre>
<h3 id="chapter-4-arvio">4.4. Arvio kieleen valittujen ratkaisujen
eduista ja haitoista</h3>
<p>Muista ohjelmointikielistä tutut <code>do/while</code>- ja
<code>switch/case</code>-lauseet on jätetty pois ja niitä ei ole
toteutettu perustellusta syystä. Samat toiminnallisuudet
pystytään toteuttamaan jo olemassa olevalla syntaksilla.
Toisaalta esimerkiksi Javasta tuttu
<code>switch-case-break</code>, jossa myös ehdon täyttävän kohdan
jälkeen tulevat kohdat suoritetaan ellei <code>switch</code>-lauseesta
oistuta erikseen <code>break</code>-lauseella,
saattaa olla hiukan työläämpää toteuttaa Pythonilla.</p>
<p>Rekursio toimii Pythonissa, mutta esimerkiksi kielen
alkuperäinen kehittäjä ei henkilökohtaisesti ole sitä mieltä,
että se olisi jokapäiväinen työkalu vaan pikemminkin teoreettinen
lähestymistapa matematiikkaan. Häntärekursiosta on olemassa
jonkinasteisia toteutuksia ja virityksiä, mutta ainakaan
virallisesti se ei ole Pythonin ominaisuus.</p>
<h2 id="chapter-5">5. Perustietotyypit</h2>
<p><em>millaisilla arvoilla tai "datalla" pelataan</em></p>
<ol class="sub-toc">
<li><span>5.1.</span><a href="#chapter-5-perustyypit">Perustyypit ja
arvoalueet</a></li>
<li><span>5.2.</span><a href="#chapter-5-vahva-heikko-tyypitys">Vahva tyypitys ~
heikko tyypitys</a></li>
<li><span>5.3.</span><a href="#chapter-5-stat-dyn-tyypitys">Staattinen tyypitys
~ dynaaminen tyypitys</a></li>
</ol>
<h3 id="chapter-5-perustyypit">5.1 Perustyypit ja arvoalueet</h3>
<p>Pythoniin on sisäänrakennettu kattava kokoelma perustyyppejä.
Pythonissa kaikki on olioita, joten varsinaisia
primitiivityyppejä ei kuitenkaan ole. Toisaalta ohut oliokääre
vaikkapa liukulukujen päällä ei ei käytännössä eroa alla olevasta
implementaatiosta mitenkään. Vastaavasti rajoittamattoman suuret
kokonaisluvut ovat ääriesimerkki päinvastaisesta tilanteesta.
Seuraavassa on listattu useimmin käytetyt tyypit. Tämä luku
perustuu CPythonin tyyppejä käsittelevään dokumentaatioon
[<a href="#ref-stdtypes">12</a>][<a href=
"#ref-datamodel">13</a>].</p>
<p>Numeeriset tyypit:</p>
<table border="1" summary="Numeeriset tyypit">
<tr>
<th>Tyyppi</th>
<th>Tarkoitus</th>
<th>Arvoalue</th>
<th>Esimerkki</th>
</tr>
<tr>
<td><code>None</code></td>
<td>NULL-arvot</td>
<td>None</td>
<td><code>None</code></td>
</tr>
<tr>
<td><code>bool</code></td>
<td>totuusarvot</td>
<td>False, True</td>
<td><code>False</code></td>
</tr>
<tr>
<td><code>int</code></td>
<td>kokonaisluvut</td>
<td>−∞ - ∞ (*)</td>
<td><code>-45353</code></td>
</tr>
<tr>
<td><code>float</code></td>
<td>kaksoistarkkuuden liukuluvut</td>
<td>(**)</td>
<td><code>3.141592653589793</code></td>
</tr>
<tr>
<td><code>complex</code></td>
<td>kompleksiluvut</td>