TDDE44 Programmering, grundkurs¶

Föreläsning 1.2¶

Johan Falkenjack, johan.falkenjack@liu.se¶

Föreläsningsöversikt Fö 1.2¶

  • Programmering i Python

Föreläsningsöversikt Fö 1.2¶

  • Programmering i Python
    • Python som miniräknare
    • Värden och datatyper
    • Variabler
    • Strängar och listor
    • Funktioner
    • Mer om strängar och listor

Scream if you want to go faster¶

  • Idag kommer det vara mycket terminologi, en del teori, extremt överdriven noggranhet blandat med överslätande ungefärliga beskrivningar.
  • Det här är fjärde gången jag håller den här föreläsningen.
    • Jag har arbetat om den från grunden varje gång baserat på mina tidigare erfarenheter.
  • Blandningen är baserat på feedback från tidigare studenter kring vad som är lätt, vad som är svårt, vad som är tydligt, och vad som kan få vara otydligt.

Fallskärm: Korta videos om Python¶

  • Inspelade av Jody Foo, som också utformat den här kursen
  • https://web.microsoftstream.com/channel/5bf65e11-e261-45aa-ab27-0ec34e2b10e4
    • (mindre kort kort URL)

Sats (eng. statement)¶

  • Pythontolken är ett program, som vilket annat program som helst. Programmet läser Pythonkod, tecken för tecken, rad för rad, och utför de instruktioner som står i Pythonkoden.
  • Varje sådan instruktion kallas för en sats.
  • Satser kan vara enkla eller sammansatta och gemensamt uttrycker de ett program, som Pythontolken utför.
  • I de enklaste fallen; ett program ungefär som en miniräknare.
In [ ]:
1

Python som miniräknare¶

  • De mest grundläggande operationerna i nästan alla programmeringsspråk är de aritmetiska operationerna.
  • De fyra räknesätten är representerade som binära operatorer: +, -, *, /
In [24]:
1-1
Out[24]:
0
In [ ]:
+
-
/
*
**
//
%

Värden och literaler¶

  • När vi själva beräknar $1+1$ så vet vi att det är det numeriska värdet 1 som skall adderas till det numeriska värdet 1 och resultatet blir det numeriska värdet 2.
  • För datorn är dock 1+1 bara en serie tecken.
  • 1 är inget värde i sig det är bara hur vi signalerar till Python att det numeriska värdet 1 skall användas.
  • Den här typen av representationer kallas för literaler (eng. literals).
    • De är den "bokstavliga" beskrivningen av ett värde.
  • Det finns ingen dold klurighet här, men det är lätt att röra till det för sig själv och tro att det måste finnas det.
  • "They literally mean what they say."
  • Formellt sett kommer ordet från att det är den textuella (jmf. "literatur") representationen av ett värde.

Datatyper¶

  • Alla värden in Python har en datatyp, och datatypen hos ett värde kan inte ändras.
    • (Python är strikt typat.)
  • Ett värdes datatyp avgör vad vi kan göra med värdet och vad som händer när vi använder det i olika sammanhang.
  • En literal representerar alltså ett specifikt värde, som har en specifik datatyp.
  • Vi kommer lära oss att känna igen typen av olika literaler under de första labbarna, de vi sett hittills är
    • int — Heltal (eng. integer)
    • float — Flyttal (eng. floating point number), det vanligaste sättet att representera decimaltal digitalt. (Ni kommer höra mycket mer om detta i TANA21/22 Beräkningsmatematik, tills dess kan ni tänka "decimaltal och ofta lite, lite fel")

Sidospår: Objekt och klasser¶

  • Ibland kommer ni höra objekt istället för värde eller klass istället för datatyp.

  • Vi kommer återvända till klasser och objekt längre fram i kursen men för tillfället kan vi betrakta dessa som synonymer till datatyp och värde.

  • I Python, till skillnad från vissa andra språk som t.ex. C/C++ eller Java, så är alla värden objekt.
  • Alla objekt tillhör en viss klass och alla datatyper i Python är formellt sett klasser.

Uttryck (eng. expression)¶

  • Vad vi såg i miniräknarexemplen var ett antal enkla matematiska uttryck.
  • Passande nog kallar vi dessa satser för uttryck även inom programmering.
  • Mer generellt: Ett uttryck är en sats som kan evalueras (beräknas) till ett värde.
    • (Dvs. alla uttryck är satser, men inte alla satser är uttryck.)
  • Värdet av ett uttryck behöver inte vara numeriskt, men mer om det senare.

Flyttal och heltal?¶

  • Pythontolken kommer automatiskt se till att resultatet av att evaluera ett uttryck har rätt datatyp under vissa omständigheter.
  • Ofta är det givet: Antag att $x, y \in \mathbb{Z}$, vi vet att
    • $x+y \in \mathbb{Z}$
    • $x-y \in \mathbb{Z}$
    • $x \cdot y \in \mathbb{Z}$
    • men vad gäller för $x/y$?
  • Eftersom vi inte vet om kvoten mellan $x$ och $y$ är ett heltal kommer Pythontolken ta det säkra före det osäkra och värdet av en division är alltid ett flyttal.
    • Detta kallas mer generellt för typinferens.
In [ ]:
2/1

Fler aritmetiska operatorer?¶

  • Potensoperatorn: **
    • (Ett vanligt misstag är att använda hatt-operatorn ^ som har helt annan betydelse i Python - bitwise XOR för den som kan sin digitalteknik.)
  • Golvdivision, division avrundat nedåt (eng. floor division): //
    • (Kallas ofta felaktigt för heltalsdivision då det är ekvivalent med heltalsdivision för positiva heltal, men inte för negativa. Felaktigt beskriven i Skansholm.)
  • Modulo, eller "restdivision": %
    • Ekvivalent med resten vid en golvdivision.

Sidospår: Varför golvdivision och inte heltalsdivision?¶

  • Golvdivision och Modulo hänger ihop: Givet att $a, b, q, r \in \mathbb{Z}^+$ så gäller att
$$\frac{a}{b} = q \text{ med resten } r \text{ så att } b \cdot q + r = a \text{ och } 0 \leq r \lt b $$
  • För att samma förhållande skall gälla när $a \in \mathbb{Z}^-$, dvs när $a \leq 0$, finns två alternativ:
    1. Trunkera $q$ (avrunda $q$ mot $0$, detta är vad Skansholm säger att // gör). Då blir $r$ negativ och olikheten $0 \leq |r| \lt b $.
    2. Avrunda $q$ mot negativa oändligheten, $\lfloor q \rfloor$. Då fortsätter $r$ att vara positiv och olikheten är oförändrad.
  • Donald Knuth m.fl. har argumenterat för att alternativ 2 leder till färre misstag (ett sådant misstag beskrivs på Wikipedia-artikeln för modulo-operationen) och Guido är uppenbarligen på Knuth's sida.
  • Detta är ett av de stora tvisteämnena bland folk som skapar programmeringsspråk och därför skiljer det mellan olika språk.
  • Dvs ((a//b)*b)+(a%b) == a

$\text{ (givet att } a \geq 0 \text{ och } b \geq 0 \text{)}$

In [ ]:
answer = 42
answer+1

Tilldelning, inte likhet¶

  • =-tecknet orsakar ofta förvirring för den som är van vid matematik.
  • I Python betyder =-tecknet tilldelning.
answer = 42
  • Utläses som tilldela variabeln answer värdet 42
  • Mer generellt tilldela variabeln till vänster om = värdet av uttrycket till höger om =

Variabel som en låda

variable_noreference.svg
  • answer = 42
  • Vi kan tänka oss att en variabel är en låda.
  • När vi gör tilldelningen ovan händer följande:
    • Pythontolken skapar en låda och skriver namnet answer på framsidan,
    • och stoppar sedan värdet 42 i lådan så att vi kan använda det igen.

Ordningen spelar roll¶

  • Vi kan inte vända på en tilldelning som vi kan göra med en matematisk likhet:
In [33]:
answer = answer + 42

hej = hej + 1
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[33], line 3
      1 answer = answer + 42
----> 3 hej = hej + 1

NameError: name 'hej' is not defined
In [34]:
print(answer = answer+1)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[34], line 1
----> 1 print(answer = answer+1)

TypeError: 'answer' is an invalid keyword argument for print()
In [26]:
42 = answer
  Cell In[26], line 1
    42 = answer
    ^
SyntaxError: cannot assign to literal here. Maybe you meant '==' instead of '='?

Tilldelning är en sats¶

  • Tilldelningsoperationen kan inte evalueras till värde i sig.
  • Tilldelning är alltså inte ett uttryck.
  • Repetition: Alla uttryck är satser, men inte alla satser är uttryck — tilldelning är en sådan sats.

En variabel är verkligen variabel¶

  • Det är tillåtet att när som helst ändra värdet av en variabel i Python.
In [37]:
answer = 1.3
In [ ]:
answer = 42
answer / 2

Bara aritmetik?¶

  • Vadå "bara"?
  • Bra sätt att börja för den med mattevana.
  • Programmering är egentligen mycket mer, speciellt när vi börjar tala om värden som inte är atomära.

Strängar, datatypen str¶

  • Eng. string, från "to string something together"; "a string of beads" → "a string of characters"
  • Representerar text och strängliteraler skrivs med citationstecken (enkla ' eller dubbla ", så länge man är konsekvent).
    • "abcd", 'efgh'
  • Man bör inte blanda citationstecken i samma fil, men...
    • Examinatorn har personligen den fula ovanan att använda ' för strängar med bara ett tecken, och " för längre strängar.
  • Python har inte en separat datatyp för tecken, "a" är identiskt med 'a' och båda är strängar.
  • Strängar och heltal är dock helt olika saker, alltså är strängen '42' inte samma sak som heltalet 42.
  • Detta kommer av språk som har en separat teckendatatyp, för enstaka tecken. I dessa språk är det vanligt att enkla citationstecken indikerar ett enskilt tecken medan dubbla citationstecken representerar strängar.

Vilka uttryck kan vi bygga med strängar?¶

  • + — utför konkatenering av strängar
  • Testa andra operatorer, vad händer med -, * och /?

Listor, datatypen list¶

  • En ordnad samling av objekt.
    • Jmf. med kataloger från när vi pratade katalogstrukturer.
  • Kan innehålla vilken annan typ av objekt som helst och vi kan blanda fritt i samma lista.
  • Listliteraler skrivs med hakparenteser, en tom lista: []
  • En lista med heltalen 1, 2 och strängen 'a': [1, 2, 'a']

Funktion¶

  • En funktion i Python är en namngiven samling med satser.
  • Mer generellt än de operatorer vi sett hittills.
  • Kan ta allt från inga till obegränsat många argument, på samma sätt som kommandon i skalet.
  • Används till alla möjliga saker, och vi skapar våra egna funktioner för att bygga nya abstraktioner.

Funktionsanrop¶

  • En typ av uttryck, då de kan evalueras till någon form av värde.
    • Jmf. $f(x)=x^2$, att evaluera $f(a)$ är att beräkna värdet av funktionen i punkten $a$.
  • Funktionen len tar ett objekt som kan sägas ha en längd, t.ex. en sträng eller en lista, och returnerar den längden.
  • Vi anropar en funktion genom att skriva dess namn följt av parenteser. Mellan parenteserna skriver vi eventuella argument till funktionen.
  • Dvs. när funktionsanropet len(s) evalueras så kommer resultatet vara längden av strängen s.
In [48]:
the_length = print('hej')
print(the_length)
hej
None

Några viktiga inbyggda funktioner¶

  • str — omvandlar ett objekt till en sträng
  • int — omvandlar ett objekt till ett heltal
  • round — avrundar ett tal
  • abs — ger beloppet av ett tal
  • min — ger det minsta värdet av två tal
  • max — ger det största värdet av två tal
  • sum — ger summan av en samling
In [50]:
print(str(42) + "42")
4242

Definiera nya funktioner¶

  • Vi definierar (skapar) egna funktioner för att
    • använda samma kod flera gånger
    • dela upp ett problem i mindre delproblem
    • göra kod lättare att läsa
  • Namngivning av funktioner
    • använd namn som beskriver vad de gör
    • använd verb-liknande namn
    • Exempel: calculate_average, get_number_of_votes

def och return¶

  • Antag att vi vill definiera en funktion som kan beräkna arean av en triangel.
  • För att göra detta använder vi den särskilda def-satsen.
In [52]:
def triangle_area(height, width):
    area = (height*width)/2
    return area

triangle_area(3, 7)
Out[52]:
10.5
  • Nu blev det mycket på en gång...

Anatomilektion¶

Vårt exempel¶

  • Förklara vad funktionen gör

Funktionsdefinition¶

  • Sammansatt sats (compound statement)
  • En klausul

Funktionsdefinition - header¶

  • Börjar med nyckelordet def följt av funktionens namn och en parameterlista inom parentes
    • Inte samma sak som datatypen list

Funktionskropp¶

  • Formellt: sammansatta satsens svit
  • Körs ej vid definition
    • Eventuella fel upptäcks inte än

Funktionsanrop¶

  • Ett uttryck, till skillnad från definitionen som bara är en sats.

Retursats¶

  • När vi betraktar ett funktionsanrop som ett uttryck:
    • Returvärdet är det värde som uttrycket får när det evalueras.

Argument och parametrar¶


No description has been provided for this image
No description has been provided for this image
  • Notera att argument refererar till faktiska värden. De kan finnas i variabler, beräknas via uttryck, eller skickas med som literaler som i det här fallet.
  • Parametrar är de variabler inne i funktionen som kommer innehålla argumentvärdena, vi säger att argumenten binds till parametrarna.

Mer om strängar¶

Osynliga tecken¶

  • Vissa tecken är "osynliga", t.ex. tab och radbrytningar
  • För att skriva dem används följande teckenkombinationer
    • tabtecken: "\t"
    • radbrytning: "\n"

Varje tecken i en sträng har ett index¶

  • Index är heltal.
  • Numreringen börjar på 0
    • Tänk att vi börjar på "nollte" position och läser ett tecken framåt för att få ut första tecknet, osv.
  • Strängen "hejsan":
h e j s a n
0 1 2 3 4 5

Åtkomst av tecken på en viss position i en sträng¶

  • Vi kan använda följande notation för att komma åt ett tecken på en viss position i en sträng
    • my_string[index]
  • my_string[0] är det första tecknet i variabeln my_string.
  • Negativa index kan användas för att titta "bakifrån"
    • my_string[-1] ger det sista tecknet i variabeln my_string

Längden på en sträng¶

  • För att ta reda på hur många tecken en sträng innehåller kan funktionen len() användas.
  • Exempel
In [ ]:
namn = "Alfred"
# tilldela variabeln namnlängd värdet som len(namn)
# returnerar
namnlängd = len(namn)
# skriv ut värdet i variabeln namnlängd
print(namnlängd)

Delsträngar¶

  • my_string[start:end] från index start, inkludera tecknen på alla index mindre än end
  • my_string[:end] från första tecknet, inkludera tecknen på alla index mindre än end
  • my_string[start:] alla tecken från index start till slutet av strängen
h e j s a n
0 1 2 3 4 5
In [ ]:
my_string = "hejsan"
my_string[1:4]

Ett värde som en sträng¶

  • Vi kan använda funktionen str() för att få en strängrepresentation av vilket värde som helst.
  • Exempel:
In [ ]:
3+3
In [ ]:
str(3) + str(3)
In [ ]:
str(True)

Mer om listor¶

Datatypen list¶

  • Används för att lagra en sekvens av värden (element i listan).
  • Listor är också värden, dvs en lista kan innehålla listor (som i sin tur kan innehålla listor osv)
  • Syntax:
studenter = ["Ada", "Bertil", "Cecilia"]
  • Det går bra att blanda datatyper i en lista:
diverse = [5, 3.0, "rosa", [100, 200, 300]]
  • Precis som med strängar använder vi index för att komma åt ett värde på en viss position.
  • Index för listor börjar också på 0

Del-listor¶

  • Vi kan även plocka fram delar av en lista
  • my_list[start:end] från index start, inkludera alla värden med index mindre än end
  • my_list[:end] från början, inkludera alla värden med index mindre än end
  • my_list[start:] från index start till slutet av listan
'h' 'e' 'j' 's' 'a' 'n'
0 1 2 3 4 5
In [ ]:
my_list = ['h', 'e', 'j', 's', 'a', 'n']
my_list[1:4]

Operatorer som kan användas med listor¶

  • Operatorn + kan användas för att slå ihop två listor till en ny lista. Ordningen spelar roll!
In [ ]:
frukter1 = ["äpple", "päron"]
frukter2 = ["apelsin", "banan"]
alla_frukter1 = frukter1 + frukter2
alla_frukter2 = frukter2 + frukter1
In [ ]:
print(alla_frukter1)
In [ ]:
print(alla_frukter2)

Ändra på ett värde i en lista¶

  • Vi kan ändra värdet på en viss position i en lista med en tilldelningssats:
In [ ]:
values = [1, 2, 3, 4]
print(values)
In [ ]:
# ändra värde på index 2
values[2] = "hoppsan"
print(values)

Lägga till nytt värde till slutet på en lista¶

In [ ]:
frukter = ["apelsin"]
print(frukter)
In [ ]:
frukter = frukter + ["banan"]
print(frukter)

Lägga till nytt värde till början på en lista¶

In [ ]:
frukter = ["apelsin"]
print(frukter)
In [ ]:
frukter = ["banan"] + frukter
print(frukter)

Metoden list.append()¶

  • Användning av operatorn + med listor ändrar inte på operanderna
    • nedanstående uttryck kommer beräknas, men resultatet sparas inte
In [ ]:
characters1 = ["a", "b", "c"]
characters1 + ["d"]
print(characters1)
  • Metoder är ett slags funktioner som man hänger på ett objekt med hjälp av punktnotation
    • Mer om metoder i Tema 4-6
  • Metoden list.append(value) lägger till value till en lista
In [ ]:
tcharacters1.append("d")
print(characters1)t

Moduler¶

Moduler¶

  • Specialiserade funktioner m.m. kan göras tillgängliga t.ex. genom att importera moduler i sin Python-kod.
  • Varje fil med Python-kod kan användas som en modul.
  • Det finns ett antal moduler som ingår i Pythons så kallade standardbibliotek (Python Standard Library).
    • Moduler i standardbiblioteket finns alltid tillgängliga i alla Python-installationer utan att behöva installera något extra.

Moduler¶

  • Tillhandahåller ytterligare funktionalitet, t.ex. funktioner för speciella tillämpningar
  • Exempel på moduler som följer med Python
    • random: har t.ex. funktioner som returnerar slumpvärden
    • sys: funktioner m.m. som har med systemet att göra (lägre abstraktionsnivå)
    • os: funktioner m.m. som har med operativsystemet att göra (högre abstraktionsnivå)

Import av modul och exempel på användning¶

  • För att få tillgång till en modul behöver den importeras med en import-sats, som oftast inleds med nyckelordet import.
  • Standard är att lägga alla importsatser i början av textfilen.
In [ ]:
import random
# funktionen random() i modulen random returnerar ett slumpmässigt
# flyttal mellan 0.0 och 1.0
slumpvärde1 = random.random()
print(slumpvärde1)
In [ ]:
# funktionen randint(heltal1, heltal2) i modulen random returnerar ett
# slumpmässigt heltal från heltal1 till och med heltal2.
slumpvärde2 = random.randint(10, 90)
print(slumpvärde2)

Import, namnrymder, punktnotation¶

  • import random
  • Ovanstående laddar in innehållet i modulen random och ser till att det hamnar i namnrymden random
  • Funktionen randint(heltal1, heltal2) i modulen random kommer man då åt genom att skriva
random.randint(heltal1, heltal2)
In [ ]:
# import-exempel 1
import random

list_of_names = ["Ada", "Bea", "Cecilia", "Dolores"]

def random_greeting1(names):
    # random.choice() väljer ut ett slumpmässigt element från
    # en sekvens
    name = random.choice(names)
    print("Hello " + name + "!")
    
def random_greeting2(names):
    # random.randint() slumpar fram ett heltal från ett slutet
    # intervall
    random_index = random.randint(0, len(names)-1)
    print("Hello " + names[random_index] + "!")
In [ ]:
random_greeting1(list_of_names)
In [ ]:
random_greeting2(list_of_names)
In [ ]:
#import-exempel 2

from random import *

list_of_names = ["Ada", "Bea", "Cecilia", "Dolores"]

def random_greeting1(names):
    # choice() från modulen random väljer ut ett slumpmässigt
    # element från en sekvens
    name = choice(names)
    print("Hello " + name + "!")

def random_greeting2(names):
    # randint() från modulen random slumpar fram ett heltal från
    # ett slutet intervall
    random_index = randint(0, len(names)-1)
    print("Hello " + names[random_index] + "!")
In [ ]:
random_greeting1(list_of_names)
In [ ]:
random_greeting2(list_of_names)