đĄ Gallium
Avainsanat
Aivan kuten BashissÀ ja PowerShellissÀ, myös Pythonissa on varattuja sanoja, joita ei voi kÀyttÀÀ muuttujaniminÀ. TÀssÀ on lista niistÀ:
False None True and as
assert async await break class
continue def del elif else
except finally for from global
if import in is lambda
nonlocal not or pass raise
return try while with yield
LisÀksi on sisÀÀnrakennettuja funktioita, joita toki voit kÀyttÀÀ muuttujaniminÀ, mutta jyrÀÀt sivuoireena Pythonin toiminnallisuuksia. TÀmÀ ei siis ole suositeltavaa. NÀitÀ ovat:
abs aiter all anext any ascii
bin bool breakpoint bytearray bytes callable
chr classmethod compile complex copyright credits
delattr dict dir display divmod enumerate
eval exec execfile filter float format
frozenset get_ipython getattr globals hasattr hash
help hex id input int isinstance
issubclass iter len license list locals
map max memoryview min next object
oct open ord pow print property
range repr reversed round runfile set
setattr slice sorted staticmethod str sum
super tuple type vars zip
Kuinka tulostettiin?
YllÀ olevat listat on tulostettu seuraavalla skriptillÀ.
import keyword
import builtins
def print_as_tabular(words:list[str], columns:int=5, margin:int=2):
# Calculate variables
column_width = max([len(x) for x in words]) + margin
# Loop and print
for batch in range(0, len(words), columns):
row_words = words[batch:batch + columns]
for word in row_words:
print(f"{word:<{column_width}}", end="")
print()
print()
# Print the reserved keywords
print_as_tabular(keyword.kwlist)
# Print the built-ins
low_case_builtins = [x for x in dir(builtins) if x[0].islower()]
print_as_tabular(low_case_builtins, columns=6)
TĂ€rpit
Muuttujat
Koko totuus löytyy Pythonin dokumentaatiosta (esim. Built-In Types), mutta alla on pikaohje, jolla pÀÀset alkuun.
Dynaaminen
Aivan kuten PowerShell, myös Python dynaamisesti tyypitetty kieli. Alla oleva esimerkki on sinulle hyvinkin tuttu PowerShellin puolelta:
x = 1 # Kokonaisluku (class 'int')
x = 3.12 # Liukuluku (class 'float')
x = "abc" # Merkkijono (class 'str')
x = [1, 2, 3] # Lista (class 'list')
x = (1,2,3) # Tuple (class 'tuple')
x = {1,2,3} # Set (class 'set')
x = {"a": 1, "b": 2} # Sanakirja (class 'dict')
x = True # Boolean (class 'bool')
x = None # NoneType (class 'NoneType')
KAMK:n opiskelijana olet kÀynyt mitÀ todennÀköisimmin Python Perusteet -kurssin, joten nÀiden pitÀisi olla sinulle tuttuja tyyppejÀ. Jos et ole varma, niin suosittelen kertaamaan materiaalia. Erityisesti listan, tuplen ja setin ero on hyvÀ tunnistaa, koska ne muistuttavat toisiaan, mutta eroavat kÀyttötarkoitukseltaan.
TyypittÀminen
Python ja PowerShell eroavat merkittÀvÀsti toisistaan tyypityksen ja tyypin vaihtamisen suhteen. Muistat toivon mukaan PowerShellistÀ, ettÀ muuttujan voi pakottaa tiettyyn tyyppin kirjoittamalla tyypin hakasulkeisiin ennen muuttujaa (esim. [int]$x = "42"
). Pythonissa on vastaava syntaksi, mutta se on vain type hint dokumentaatiota varten, ei pakottava tyypitys. Alla esimerkki:
đŠ Terminologia
Termi, jota kÀytetÀÀn Pythonin ÀÀrimmÀisen liberaalista tyypityksestÀ, on duck typing. Lause, johon kenties olet jo törmÀnnyt, mÀÀrittelee sen nÀin: If it looks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck.
Pythonin tyypitys on siis vapaaehtoista, mutta se ei tarkoita, ettÀ sitÀ ei kannattaisi kÀyttÀÀ. KevyimmillÀÀn kannattaa mÀÀrittÀÀ type hinting tyylillÀ. KÀyttÀmÀsi IDE, kuten Visual Studio Code lisÀosineen, osaa hyödyntÀÀ tÀtÀ tietoa ja tarjota parempaa koodiautomaatiota ja -tarkistusta.
Ulkoista apua
Dynaaminen tyypitys ei ole kaikkien mieleen, ja se altistaa koodin virheille, jotka voitaisiin havaita staattisella tyypityksellÀ. Tyyppivirheisiin perustuvat bugit ovat usein vaikeita löytÀÀ ja korjata. TÀmÀn vuoksi on olemassa työkaluja, jotka tarkistavat koodin tyypityksen ennen sen suorittamista. Visual Studio Codessa on Microsoftin yllÀpitÀmÀ ja tÀten hyvinkin virallinen lisÀosa Python, jonka mukana asentuu vakiona Pylance. JÀlkimmÀisen voi vaihtaa sen tuoreeseen kilpailijaan nimeltÀÀn Ruff tai mypy.
Tutustumme Visual Studion Coden asetuksiin tarkemmin live-tunneilla. TÀssÀ materiaalissa neuvotaan työkalujen kÀyttö Dockerin avulla yhtÀ skriptiÀ vasten.
Aloitetaan työkalulla nimeltÀÀn mypy.
# Run mypy against a single script
docker run --rm -v $(pwd):/data:ro cytopia/mypy scripts/hello_turbo.py
# Or maybe with a strict mode to be more pedantic
docker run --rm -v $(pwd):/data:ro cytopia/mypy --strict scripts/hello_turbo.py
Tuore haastaja Python-ekosysteemissÀ on Astral, jonka työkalu Ruff toimii sekÀ linterinÀ ettÀ formatterina. Linter tarkistaa koodin virheistÀ ja formatter muotoilee koodin yhtenÀiseen tyyliin. SitÀ voit kÀyttÀÀ Dockerin kautta nÀin:
# Tarkista virheet
docker run --rm -v $(pwd):/io ghcr.io/astral-sh/ruff:latest check scripts/hello_turbo.py
# Korjaa automaattisesti virheet (1)
docker run --rm -v $(pwd):/io ghcr.io/astral-sh/ruff:latest check scripts/hello_turbo.py --fix
# Muotoile teksti vakiotyyliin
docker run --rm -v $(pwd):/io ghcr.io/astral-sh/ruff:latest format scripts/hello_turbo.py
Warning
Ruff-komennot ajetaan ilman :ro
eli read-only volumea. Ruff tarvitsee kirjoitusoikeudet muokatakseen tiedostoa ja luodakseen vÀliaikaisia tiedostoja. NÀmÀ tiedostot ilmestyvÀt .ruff_cache
-hakemistoon. KylkiÀisenÀ tulee .gitignore
-tiedosto, joka estÀÀ nÀiden tiedostojen pÀÀtymisen versionhallintaan.
VianetsintÀ
BashistÀ ja PowerShellistÀ tuttu echo
-komennon vastine Pythonissa on print
. Hyvin primitiivinen, mutta silti tehokas tapa debugata koodia on tulostaa muuttujien arvoja konsoliin.
Assert
On tilanteita, joissa haluat skriptin kaatuvan, jos jokin ehto ei tÀyty. TÀmÀ onnistuu assert
-lausekkeella. Alla esimerkki:
Logging
Toivon mukaan muistat yhÀ PowerShellin puolelta eri virrat, joihin pystyy kirjoittamaan viestejÀ. Pythonissa vastaava toiminnallisuus löytyy logging
-moduulista. Alla esimerkki:
import logging
import random
def pick_random_level() -> int:
level = random.choice(
[
logging.DEBUG,
logging.INFO,
logging.WARNING,
logging.ERROR,
logging.CRITICAL,
]
)
name = logging._levelToName[level]
print(f"Randomly chosen level: {name} (no. {level})")
return level
# Set the logging level and format
rnd_level = pick_random_level()
FORMAT: str = "%(asctime)s - %(levelname)s - %(message)s"
logging.basicConfig(level=rnd_level, format=FORMAT, datefmt="%H:%M:%S")
# Call each level once
logging.critical("DON'T PANIC!")
logging.warning("It worked on my machine...")
logging.error("Have you tried turning it off and on again?")
logging.info("Must be a cosmic ray. Try running it again.")
logging.debug("I'm sure it's just a typo.")
Skripti arpoo satunnaisen loggaustason ja tulostaa viestin jokaisella tasolla. Vain valitun tason ylittÀvÀt viestit tulostuvat konsoliin. Alla esimerkki skriptin ajosta:
$ ./runpy.py scripts/logger_practice.py
Randomly chosen level: INFO (no. 20)
11:24:23 - CRITICAL - DON'T PANIC!
11:24:23 - WARNING - It worked on my machine...
11:24:23 - ERROR - Have you tried turning it off and on again?
11:24:23 - INFO - Must be a cosmic ray. Try running it again.
TehtÀvÀt
TehtÀvÀ: DevausympÀristö ja runpy.py
Loit ajo aiemmassa tehtÀvÀssÀ python/
-hakemiston, jotta sait kopioitua skriptin avulla virtuaalikoneesta kaikki Python-srkriptit sinun host-koneellesi. Jatketaan saman hakemiston kÀyttöÀ, mutta Multipass-koneen sijaan kÀytetÀÀn Docker-konttia. LisÀksi Bash-skriptin sijasta kÀytÀmme Python-skriptiÀ. Vaiheet:
- Lataa gh:sourander/skriptiohjelmointi/exercise-assets/scripts/runpy.py
- Tee tiedostosta ajettava (tai aja jatkossa
python runpy.py
) - Lue tiedoston sisÀltö lÀpi ja selvitÀ, mitÀ se tekee.
Referenssiksi hakemistorakenteen kuuluisi olla:
TehtÀvÀ: Python Hello World
Luo skripti hello.py
, joka tulostaa konsoliin Hello, World!
. Aja sitten:
$ ./runpy.py --dryrun scripts/hello.py
[DRY] Cmd that would run: LUE TĂMĂ OUTPUT!!
$ ./runpy.py scripts/hello.py
Hello, World!
$ ./runpy.py --bash --dryrun
[DRY] Cmd that would run: LUE TĂMĂ OUTPUT!!
$ ./runpy.py --bash
# python3 /app/scripts/hello.py
Hello, World!
Huomaa, ettÀ tiedoston ei tarvitse olla executable, koska kontin sisÀllÀ ajetaan komento python <tiedosto>
eikÀ ./<tiedosto>
.
TehtÀvÀ: Python Turboahdettu Hello World
Luo skripti, joka tulostaa:
- absoluuttinen polku työhakemistoon
- absoluuttinen polku skriptin sijaintiin
- polut, joista Python etsii moduuleja
Tiedoston tulisi alkaa nÀin:
Alla esimerkkikÀyttö Dockerin kanssa:
$ runpy.py scripts/hello_turbo.py
========= Turbo Hello World! =========
Current working dir: : /app
Skriptin sijainti: : /app/scripts/hello_turbo.py
Python moduulien hakupolut:
/app/scripts
/usr/local/lib/python312.zip
/usr/local/lib/python3.12
/usr/local/lib/python3.12/lib-dynload
/usr/local/lib/python3.12/site-packages
Ja tÀssÀ vielÀ Multipassin kanssa:
$ multipass launch --name helloturbo 24.04
$ multipass transfer scripts/hello_turbo.py helloturbo:.
$ multipass exec helloturbo -- python3 hello_turbo.py
========= Turbo Hello World! =========
Current working dir: : /home/ubuntu
Skriptin sijainti: : /home/ubuntu/hello_turbo.py
Python moduulien hakupolut:
/home/ubuntu
/usr/lib/python312.zip
/usr/lib/python3.12
/usr/lib/python3.12/lib-dynload
/usr/local/lib/python3.12/dist-packages
Vinkki: Moduulit
Katso, mitÀ sys.path
sisÀltÀÀ. Huomaa, ettÀ sys
-moduuli pitÀÀ importoida ensin.
TehtÀvÀ: Interaktiivinen Python
Harjoittele tÀssÀ tehtÀvÀssÀ interaktiivista Python ShelliÀ eli REPL:iÀ kontin sisÀllÀ. Saat sen auki ajamalla aiemmin lataamasi runpy.py
-skriptin ilman argumentteja. Kokeile seuraavia:
- Laske 2+2
- Luo muuttuja
x
ja anna sille arvoksi 42 - Tulosta muuttujan
x
arvo - Luo lista
lista
ja anna sille arvoksi[1, 2, 3]
- Tulosta listan
lista
arvot
$ runpy.py
Python 3.1x.x (main, ...) [GCC xx.x.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> # TÀssÀ voit kirjoittaa Python-koodia
Kun olet valmis, voit poistua painamalla Ctrl+D
tai kirjoittamalla exit()
.
Miksi REPL?
Interaktiivinen Python on hyvÀ tapa kokeilla nopeasti koodinpÀtkiÀ ja testata, miten Python toimii. Materiaalin kirjoittanut opettaja kÀyttÀÀ sitÀ usein myös nopeana laskimena.
TehtÀvÀ: Interaktiivinen Python Pt. 2
ĂĂ€rimmĂ€isen nĂ€ppĂ€rĂ€ komento lyhyitĂ€ skriptejĂ€ debugatessa on -i
-flagi, joka jÀttÀÀ Pythonin auki skriptin suorituksen jÀlkeen interaktiiviseen tilaan. Dokumentaatiossa se on mÀÀritelty nÀin: "When a script is passed as first argument (...) enter interactive mode after executing the script (...)" 1. Lokaalisti ajettuna se olisi nÀinkin helppoa:
$ ./runpy.py --dryrun --interactive scripts/hello_turbo.py
[DRY] Cmd that would run: LUE TĂMĂ OUTPUT!!
$ ./runpy.py --interactive scripts/hello_turbo.py
========= Turbo Hello World! =========
Current working dir: : /app
Skriptin sijainti: : /app/scripts/hello_turbo.py
Python moduulien hakupolut:
/app/scripts
/usr/local/lib/python312.zip
/usr/local/lib/python3.12
/usr/local/lib/python3.12/lib-dynload
/usr/local/lib/python3.12/site-packages
>>>
MitĂ€ me voitimme? Sinulla on kaikki skriptissĂ€ importatut moduulit kĂ€ytössĂ€, kuten myös muuttujat ja funktiot. TĂ€mĂ€ on yksi monista vaihtoehdoista debugata ja/tai kehittÀÀ skriptejĂ€. Kukin skriptaaja löytÀÀ oman tyylinsĂ€, joka sopii parhaiten omaan tapaansa työskennellĂ€ â on kuitenkin hyvĂ€ tuntea vaihtoehdot eikĂ€ tarttua ensimmĂ€iseen. Omia työskentelytapojaan kannattaa myös jatkuvasti haastaa ja kehittÀÀ.
TehtÀvÀ: Tiedostoon loggaus
Ota mallia yllÀ olevasta logger_practice.py
-skriptistÀ ja luo oma skripti, joka loggaa viestit konsolin sijasta tiedostoon (esim. logger_practice.log
). Pythonin oma Logging HOWTO on hyvÀ paikka aloittaa.
Tip
Huomaa, ettÀ jos ajat skriptiÀ kontin sisÀllÀ, niin tiedosto tallentuu kontin sisÀlle. EthÀn yritÀ tallentaa tiedostoa /app
-hakemistoon, koska se on read-only. Voit tallentaa tiedoston esimerkiksi /tmp
-hakemistoon.
Muista myös, ettÀ kontti on vÀliaikainen, joten tiedosto katoaa, kun kontti tuhotaan. On kannattavaa ajaa kontti siten, ettÀ CMD on bash, ja kÀyt suorittamassa skriptin kÀsin. Eli siis:
...joka avaa bashin kontin sisÀllÀ. TÀmÀn jÀlkeen voit ajaa skriptin kÀsin ja kÀydÀ tarkistamassa, ettÀ tiedosto on luotu.
TehtÀvÀ: Ruff
YllÀ on esitelty Ruff-työkalun kÀyttö Docker-kontissa. KÀytÀ sitÀ ja korjaa kaikkien tiedostojen virheet (sekÀ check ettÀ format), jotka olet tÀhÀn asti luonut scripts/
-hakemistoon.
Saat kÀyttÀÀ parhaaksi katsomallasi tavalla joko Dockerissa ajettua Ruffia, lokaalisti asettua Ruff:ia (esim. uv tool install ruff
) tai Visual Studio Coden lisÀosaa. Docker on helpoin, koska se on neuvottu yllÀ. Muita varten sinun tarvitsee ottaa omatoimisesti selvÀÀ.
Warning
Muista ottaa tĂ€mĂ€ tavaksi jatkossa! On oletus, ettĂ€ kurssilla kirjoittamasi skriptit lĂ€pĂ€isevĂ€t Ruffin tarkistukset. Kenties haluat kirjoittaa skriptin, joka ajaa pitkĂ€n Docker-komennon puolestasi? đ€
LĂ€hteet
-
Python Docs. Command line and environment. https://docs.python.org/3/using/cmdline.html#cmdoption-i ↩