Uke 11 - modules / import / standardbibliotek

Eksempler

Eksempel 1

Vi kan gjenbruke funksjoner og variabler fra en annen fil med import. Her er en fil med noen nyttige innhold (du kan laste ned filen her: eks_1_lib.py). Den slags fil også kaller man for modul/library:

# Vi kan definere funksjoner...

def fib(n):
    """Return the fibonacci sequence up to n as a list"""
    a, b = 0, 1
    seq = []
    while a < n:
        seq.append(a)
        a, b = b, a+b
    return seq

        
def collatz(n):
    """Return the collatz sequence from n as a list"""
    def collatz_step(n):
        if n % 2 == 0:
            return n//2
        else:
            return 3*n + 1
    seq = [n]
    while n > 1:
        n = collatz_step(n)
        seq.append(n)
    return seq

# ...eller verdier i en bibliotek

# speed of light [m/s]
C_LIGHT = 299792458

# Planck constant [Js]
H_PLANCK = 6.62607015e-34

I hovedprogrammet kan vi gjenbruke filen i ulike måter: Vi kan import-e hele filen med sitt navn, eller vi kan gi et nytt navn med import .. as. Se hvordan vi bruker funksjoner fra filen.

En annen mulighet er å plukke ut spesifikke funksjoner med from .. import .... Vi kan også bruke as her. (du kan laste ned hovedprogrammet her: eksempel_1.py)

print('Option 1')
import eks_1_lib

fib_1 = eks_1_lib.fib(100)
col_1 = eks_1_lib.collatz(17)
print(fib_1)
print(col_1)

#################################

print('Option 2')
import eks_1_lib as el

print(el.collatz(5))
c = el.C_LIGHT
print(c,'m/s')

#############################

print('Option 3')
from eks_1_lib import fib

fib_2 = fib(75)
print(fib_2)

##############################

print('Option 4')
from eks_1_lib import H_PLANCK as h, C_LIGHT as c, fib
print(c)
print(h)
print(fib(30))

Pass på at begge filene ligger i den samme mappen, og at terminalen kjører der.

Ved bruk av import kan man strukturere store programmer på en oversiktlig måte, gjerne også i flere mapper. Det går utover pensum her, men mer informasjon finnes på https://docs.python.org/3.8/tutorial/modules.html

Standardbiblioteker

Mange nyttige biblioteker er allerede med i hver Python-installasjon, det er «Python Standard Library». Vi skal vise noen eksempler av nyttige moduler her.

En full oversikt finnes på Pythons hovedsiden: https://docs.python.org/3.8/library/ Når man kommer til å jobbe mer med Python er det lurt å bli kjent med oversikten her. Man trenger ikke å være ekspert i alle modulene, men man må ha en idé hva slags moduler det finnes. Moduler som sys eller os er brukt i nesten alle prosjektene, mens biblioteker som f.eks sunau (Read and write Sun AU audio files) har en veldig spesialisert målgruppe.

Dokumentasjonen for hvert bibliotek er veldig bra, med mange eksempler. Det finnes alltid noe nyttig når man leser gjennom.

Eksempel 2

Pythons bibliotek math inneholder mange vanlige matematiske funksjoner og konstanter. Du finner dokumentasjonen for biblioteket på https://docs.python.org/3.8/library/math.html.

Her er noen eksempler på bruk av math (du kan laste ned koden her: eksempel_2.py):

import math

# The floor and ceiling functions
print(f"{4 / 3 = }")
print(f"{math.floor(4 / 3) = }")
print(f"{math.ceil(4 / 3) = }")

print()

# The constant e and powers of it
print(f"{math.e = }")
print(f"{math.exp(1) = }")
print(f"{math.exp(0) = }")
print(f"{math.exp(2) = }")

print()

# Logarithms
print(f"{math.log(math.e) = }")
print(f"{math.log(1) = }")
print(f"{math.log(5) = }")

print()

print(f"{math.log2(2) = }")
print(f"{math.log2(1) = }")
print(f"{math.log2(5) = }")
print(f"{math.log2(8) = }")

print()

print(f"{math.log10(10) = }")
print(f"{math.log10(1) = }")
print(f"{math.log10(5) = }")
print(f"{math.log10(100) = }")

print()

# Exponentials
print(f"{math.pow(2, 3) = }")
print(f"{math.pow(2, math.log2(3.3)) = }")
print(f"{math.pow(4, 1 / 2) = }")
print(f"{math.sqrt(4) = }")
print(f"{math.sqrt(math.pow(3, 4)) = }")
# print(f"{math.sqrt(-1) = }")  # This raises an error
# Use the library 'cmath' for complex numbers

print()

from math import pi

print(f"{pi = }")
# The trigonometric functions take input in radians, not degrees
# What should all these values be?
print(f"{math.sin(pi / 2) = }")
print(f"{math.sin(pi) = }")
print(f"{math.cos(pi / 2) = }")
print(f"{math.cos(pi) = }")
print(f"{math.tan(pi) = }")
print(f"{math.tan(pi / 2) = }")

Det finnes også andre bibliotek for å gjøre beregninger. Her er en liste på numeriske biblioteker. Se på noen av dem og lag dine egne eksempler.

Eksempel 3

Om man trenger en kalender eller må beregne tidspunkt, er det best å bruke en ferdig bibliotek. I Python er det datetime.

Les gjennom siden og se på eksemplene der. Filen eksempel_3.py viser noen enkle bruk av biblioteken:

from datetime import date
today = date.today()
my_birthday = date(today.year, 6, 24)

if my_birthday < today:
    my_birthday = my_birthday.replace(year=today.year + 1)

time_to_birthday = abs(my_birthday - today)
print(time_to_birthday)




from datetime import datetime
now = datetime.now()
exam = datetime(2020, 11, 30, 9, 0, 0)
print(exam - now)

Prøv å legge inn noe du fant i dokumentasjonen.

Eksempel 4

Når vi vil telle antall kan vi bruke klassen Counter i biblioteket collections, som er en spesiell versjon av dict(), hvor hvert element begynner med 0 allerede. Dokumentasjonen finner du her: collections.

Vi prøver igjen å telle antall ord i en tekst, men denne gangen bruker vi Counter. Du kan laste ned koden her: eksempel_4.py.

from collections import Counter

text = """Alice was beginning to get very tired of sitting by her sister
            on the bank, and of having nothing to do: once or twice she had peeped
            into the book her sister was reading, but it had no pictures
            or conversations in it, 'and what is the use
            of a book,' thought Alice 'without pictures or conversation?'"""

letter_count = Counter() # instead of dict() or {}

# Count letters
for let in text:
    let = let.lower()
    if let in "abcdefghijklmnopqrstuvwxyz":
        letter_count[let] += 1
# With Counter we don't have to first create a key for every letter

for let, count in letter_count.items():
    print(f"{let} is used {count:3d} times")

print("\n\n\n")


word_count = Counter()

for word in text.split():
    word = word.lower()
    word_count[word] += 1
# With Counter we don't have to first create a key for every word

# The 5 most used words, Counter has a useful helper function most_common()
# we don;t need to sort ourselves
print("The 5 most common words")
for w, c in word_count.most_common(5):
    print(f"{w:14} is used {c:3d} times")

Eksempel 5

itertools-biblioteken gjør det enklere å skrive ulike typer løkke. Filen eksempel_5.py viser et tilfelle, men det finnes mange eksempler i dokumentasjonen. Gjerne prøv noen av dem.

import itertools

print('All DNA triples')

bases = 'ATGC'
# for i in bases:
#     for j in bases:
#         for k in bases:
#             print(i+j+k)

for i,j,k in itertools.product(bases, repeat=3):
    print(i+j+k)

Eksempel 6

Du kan bruke biblioteket random til å generere tilfeldige tall. Dokumentasjonen for dette biblioteket finner du her.

Du kan laste ned koden her: eksempel_6.py. Prøv å kjør koden noen ganger uten random.seed(123456) og noen ganger med random.seed(123456). Hva er forskjellen?

import random

# random.seed(123456) # reproduserbare resultater, ulik for hver int

# heltall
print(f"{random.randint(1,6) = }")  #  1 <= N <= 6

# ulike utvalg fra en sekvens
print(f"{random.choice('abcdef') = }")
print(f"{random.choice([11, 7.2, 'foo']) = }")
print(f"{random.choices('abcdefghi', k=10) = }")
print(f"{random.sample('abcdefghi', k=3) = }")

# shuffling
xs = [1, 2, 3, 4, 5, 6, 7, 8, 9]
random.shuffle(xs)
print(f'shuffled 1: {xs}')
random.shuffle(xs)
print(f'shuffled 2: {xs}')
random.shuffle(xs)
print(f'shuffled 3: {xs}')

# float
print(f"{random.random() = }")  # [0.0, 1.0)
print(f"{random.uniform(12.0, 20.0) = }")  #  12.0 <= N <= 20.0
print(f"{random.gauss(mu=40.0,sigma=12.0) = }")

Oppgaver

Del 1 - random

Sriv en funksion kast_n_2(n) som tar inn et heltall n og simulerer n kast av to terninger (random.randint(1,6)) og legger til summen av de to i en liste. Returner den listen (som nå inneholder n elementer med tall mellom 2 og 12).

Hvor ofte får vi øyesummen 2, 3, …, 12? Bruk collections.Counter i en funksjon print_histo(xs) som tar inn en slik liste og printer ut et enkelt histogram hvor '*' står for 1%.

 2 **
 3 ***
 4 *****
...
10 ***
11 **
12 *

(Ikke bruk random.seed() slik at testene kan fungere rett.)

Del 2 - datetime, Project Euler nr.19

How many Sundays fell on the first of the month during the twentieth century (1 Jan 1901 to 31 Dec 2000)?

Del 3 - egen statistikk

Lag et bibliotek del_3_lib.py i den samme mappen sånn at det følgende programmet fungerer, men uten å bruke de eksisterende funksjonene mean,median,mode,max,min fra Python:

import del_3_lib

data = [3, 1, 7, -3, 5, 9, 1, 5, 9, 7, -3, 7]

a = del_3_lib.mean(data)
b = del_3_lib.median(data)
c = del_3_lib.mode(data)
d = del_3_lib.max(data)
e = del_3_lib.min(data)

print(a,b,c,d,e)

Alle funksjonene skal ta en liste som argument.

  • Funksjonen mean() skal returnere gjennomsnittet av tallene i listen. Gjennomsnittet av tallene \(x_1, x_2, ..., x_n\) kan beregnes med formelen:

    \[\frac{x_1 + x_2 + ... + x_n}{n}.\]

    For eksempel:

    del_3_lib.mean([2, 5, 3, 1]) # skal returnere 2.75
    
  • Funksjonen median() skal returnere medianen av tallene i listen. Dette er tallet som er i mitten etter att listen er blitt sortert. Om lengden av listen er jevn er medianen gjennomsnittet av de to tallene i mitten. For eksempel:

    del_3_lib.median([4, 12, 3, 9, 5]) # skal returnere 5
    del_3_lib.median([3, 6, 93, 45, 14, 22]) # skal returnere 18
    
  • Funksjonen mode() skal returnere typetallet: det vanligste tallet i listen. Om flere tall er like vanlige skal funksjonen returnere det tallet som er først i listen. For eksempel:

    del_3_lib.mode([3, 4, 22, 7, 4, 15, 4, 7, 1]) # skal returnere 4
    del_3_lib.mode([3, 22, 7, 4, 15, 4, 7, 1, 4, 7, 22, 15, 22]) # skal returnere 22
    
  • Funksjonen max() skal returnere den største verdien i listen. For eksempel:

    del_3_lib.max([3, 6, 93, 45, 6, 14, 22]) # skal returnere 93
    
  • Funksjonen min() skal returnere den minste verdien i listen. For eksempel:

    del_3_lib.min([3, 6, 93, 45, 6, 14, 22]) # skal returnere 3
    

Del 4 (uten tests)

Project Euler 89 er en god øvelse for dict og filhåndtering.