Föreläsningsöversikt Fö 1.1 - 1.3¶
IntroduktionKursadminLinux och datorerPython interaktivt och som skriptRättningsskriptetProgrammeringskonceptLiteraler och datatyperSatser och uttryckProgramflöde — funktioner- Strängar, listor och tupler
- Moduler
- Programflöde — villkor och sanningsuttryck
Kort repetition¶
In [1]:
def add_two(value):
return value + 2
In [2]:
my_number = 5
print(add_two(my_number))
7
In [3]:
print(my_number)
5
In [4]:
print(print(add_two(my_number)))
7 None
Inte bara tal och aritmetik
-
answer = 42 - Vadå "bara"?
- Programmering är egentligen mycket mer, speciellt när vi börjar tala om värden som inte är atomära.
Sekvenser och samlingar¶
- Sekvenser: Värden som kan delas upp i delar som har en strikt ordning. T.ex.
- Sträng:
str - Listor:
list - Tupler:
tuple
- Sträng:
- Samlingar: Värden som i sig innehåller andra värden. T.ex.
- Listor:
list - Tupler:
tuple - Associationstabeller:
dict - Mängder:
set
- Listor:
Gemensamt för sekvenser i Python¶
- Har en längd som vi kan ta reda på genom att anropa funktionen
lenmed sekvensen som argument. - Operatorerna
+och*fungerar oftast på samma sätt för alla sekvenstyper. - Vi kan indikera enskilda element eller delsekvenser med hjälp av Pythons subskriptnotation och reglerna för indexering.
Demonstration av listor, strängar och tupler¶
Strängar, datatypen str¶
- Eng. string, från "string together"; t.ex. "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.
- Examinatorn har personligen den fula ovanan att använda
- 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 heltalet42.
Vilka uttryck kan vi bygga med strängar?¶
+— utför konkatenering av strängar- Testa andra operatorer, vad händer med
-,*och/?
Osynliga tecken¶
- Vissa tecken är "osynliga", t.ex. tabtecken och radbrytningar
- Specialtecken skrivs ofta med särskilda teckenkombinationer, t.ex.
- tabtecken:
"\t" - radbrytning:
"\n"
- tabtecken:
"\tIndragen text avslutad med radbrytning.\n"
Varje tecken i en sträng har ett index¶
- Index är heltal.
- Numreringen börjar på 0
- Strängen
"EXEMPEL":
Å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 variabelnmy_string.- Negativa index kan användas för att titta "bakifrån"
my_string[-1]ger det sista tecknet i variabelnmy_string
Längden av 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 [5]:
name = "Alfred"
name_length = len(name)
print(name_length)
6
Delsträngar¶
my_string[start:end]från indexstart, inkludera tecknen på alla index mindre änendmy_string[:end]från första tecknet, inkludera tecknen på alla index mindre änendmy_string[start:]alla tecken från indexstarttill slutet av strängen
In [6]:
my_string = "EXEMPEL"
my_string[1:4]
Out[6]:
'XEM'
Ett värde som en sträng¶
- Vi kan använda funktionen
strför att få en strängrepresentation av vilket värde som helst. - Exempel:
In [7]:
3+3
Out[7]:
6
In [8]:
str(3) + str(3)
Out[8]:
'33'
In [9]:
str(True)
Out[9]:
'True'
Listor, datatypen list¶
- Används för att lagra en ordnad samling av värden (element i listan).
- 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
Dellistor¶
- Vi kan även plocka fram delar av en lista
my_list[start:end]från indexstart, inkludera alla värden med index mindre änendmy_list[:end]från början, inkludera alla värden med index mindre änendmy_list[start:]från indexstarttill slutet av listan
In [10]:
my_list = ['h', 'e', 'j', 's', 'a', 'n']
my_list[1:4]
Out[10]:
['e', 'j', 's']
Operatorer som kan användas med listor¶
- Operatorn
+kan användas för att konkatenera två listor till en ny lista. - Operatorn
*kan användas med ett heltal $n$ för att skapa en ny lista som är $n$ upprepningar av elementen i den ursprungliga listan.
In [11]:
fruits1 = ["apple", "pear"]
fruits2 = ["orange", "banana"]
all_fruits1 = fruits1 + fruits2
all_fruits2 = fruits2 + fruits1
In [12]:
print(all_fruits1)
['apple', 'pear', 'orange', 'banana']
In [13]:
print(all_fruits2)
['orange', 'banana', 'apple', 'pear']
Lägga till nytt värde till slutet på en lista¶
In [14]:
fruits = ["orange"]
print(fruits)
['orange']
In [15]:
fruits = fruits + ["banana"]
print(fruits)
['orange', 'banana']
Lägga till nytt värde till början på en lista¶
In [16]:
fruits = ["orange"]
print(fruits)
['orange']
In [17]:
fruits = ["banana"] + fruits
print(fruits)
['banana', 'orange']
Tupler, datatypen tuple¶
- En ordnad samling av objekt.
- Fungerar nästan exakt som listor, än så länge. Vi kommer se skillnaden längre fram i kursen. Fram till mitten av labb 2 kommer vi behandla dem identiskt.
- Kan innehålla vilken annan typ av objekt som helst och vi kan blanda fritt i samma tupel.
- Tupelliteraler skrivs som listor men med vanliga parenteser istället för hakparenteser, men med två specialfall:
- Det finns ingen litteral för en tom tupel, istället skapar vi en tom tupel med funktionsanropet
tuple(). - En tupel med bara ett element måste ha ett komma efter det elementet:
(1,)
- Det finns ingen litteral för en tom tupel, istället skapar vi en tom tupel med funktionsanropet
- En tupel med heltalen
1,2och strängen'a':(1, 2, 'a')
Hur vi ofta tänker på 0-indexerade sekvenser
sequence[0] eller sequence[1].Hur vi ofta tänker på 0-indexerade sekvenser
Ett bättre sätt att tänka på 0-indexerade sekvenser
Ett bättre sätt att tänka på 0-indexerade sekvenser
'M' kan vi gå vi till -4 och läsa ett element framåt.Ett bättre sätt att tänka på 0-indexerade sekvenser
-0" respektive 7 skulle se ut på det här sättet.(Här blir det förhoppningsvis också tydligt varför det blir fel om vi går till index
7 och försöker läsa ett element framåt.)Index som offset¶
- Sekvenser lagras ofta i så kallade fält (på engelska, och ofta på vedertagen svengelska: array) i minnet, dvs. i direkt följd från en viss minnesadress.
- (Fortfarande mestadels sant.)
- För att komma åt ett element på en viss position i sekvensen användes ett offset som indikerade hur många steg från sekvensens start man behövde gå för att komma till elementet man ville läsa.
- Minnesadressen för fältet pekade på början av första elementet i fältet och första elementet låg alltså på sekvensens minnesadress + offset $0$.
- Alltså: Index som börjar på $0$ är ekvivalent med offset.
In [18]:
spam = "EXEMPEL"
- Vi antar att
spamlagras på minnesplats0x0007
Exempel¶
In [19]:
print(spam)
EXEMPEL
- Om vi skriver ut variabeln
spamfår vi sekvensen som börjar på minnesadressen0x0007och är 7 tecken lång
Exempel¶
In [20]:
print(spam[0])
E
- Om vi använder indexering tar vi sekvensens minnesadress, adderar index-värdet, och läser ett element framåt från den beräknade minnesadressen
Exempel¶
In [21]:
print(spam[1])
X
- Om vi använder indexering tar vi sekvensens minnesadress, adderar index-värdet, och läser ett element framåt från den beräknade minnesadressen
Exempel¶
In [22]:
print(spam[2:5])
EMP
- Om vi använder "utsnitt" (eng. slice, och ofta på vedertagen svengelska) adderar start- och stopvärdena till sekvensens minnesadress och läser från den den första och fram till den andra beräknade minnesadressen.
Sidospår: Indexering från 0 eller 1¶
- BCPL (1967) var det första programmeringsspråket att helt enkelt exponera den underliggande egenskapen att indexering är ekvivalent med pekararitmetisk offset och numrera index från 0.
- Det följde sedermera med till programmeringsspråket C (som inspirerades av BCPL), varifrån det spred sig till att bli norm för nästan alla moderna programmeringsspråk.
- Matematikspråk som MATLAB/Octave, R, och Julia skiljer sig dock från mängden och indexerar från 1. Riktigt mastiga språk som Fortran låter programmeraren bestämma själv, det behöver inte ens vara positiva heltal. Galningar.
- Ja, man gör bort sig hela tiden när man växlar mellan 0-indexerande och 1-indexerande språk.
- Till er som målgrupp kan jag bara säga: Vänj er vid att dubbelkolla.
- Det finns goda argument för att indexera från 0 som är oberoende av den historiska kopplingen till fält:
- Why numbering should start at 0 av Edsger Dijkstra.
- Mer om historien bakom hur 0-indexering blev en grej (och en beskrivning av föregående referens som "unresearched hippie voodoo nonsense"):
Styra programflöde med villkor¶
In [23]:
def plot_prices(degree):
import numpy as np
import matplotlib.pyplot as plt
x = [0, 12, 18, 65]
y = [0, 20, 30, 15]
poly = np.polyfit(x, y, deg=degree)
polyval = np.polyval(poly, range(100))
fig, ax = plt.subplots()
ax.plot(polyval, label=f'{degree} degree polynomial')
ax.legend()
return polyval
In [24]:
prices = plot_prices(3)
In [25]:
prices[12]
Out[25]:
np.float64(19.999999999999996)
Vad i he...¶
Villkorssatser, en bättre lösning¶
if-satsen¶
- Sammansatt sats med en eller flera klausuler.
- Första klausulen börjar alltid med nyckelordet
ifföljt av ett sanningsuttryck (eng. boolean expression), dvs ett uttryck som evalueras till ett sanningsvärde (eng. boolean value). - Syntax:
if <boolean expression>:
# Code block that runs if boolean is True
Vad är en "boolean"?
- Booleska värden, (eng. boolean value), ett annat ord för sanningsvärden.
- I Python: Klassen
boolmed exakt två möjliga värden,TrueellerFalse. - Ofta resultat av någon jämförelseoperator:
==,!=,<,>,<=,>=.
In [26]:
print(1 <= 2)
True
In [27]:
def get_price(rider_age):
price = 30
if rider_age < 12:
price = 0
return price
In [28]:
print(get_price(12))
30
else-klausulen¶
- En del av en sammansatt sats, i det här fallet en
if-sats. - Alltid den sista klausulen och hanterar en "annars"-situation.
- Syntax:
if boolean:
# Code that runs if boolean is True
else:
# Code that runs if boolean is False
In [29]:
def get_price(rider_age):
if rider_age < 12:
price = 0
else:
price = 30
return price
In [30]:
print(get_price(38))
30
Bara en klausul kommer att köras¶
- Dvs. vi behöver inte variabeln
price.
In [31]:
def get_price(rider_age):
if rider_age < 12:
return 0
else:
return 30
In [32]:
print(get_price(38))
30
Men vi hade ju fyra fall i vårt första exempel!¶
- Två olika lösningar som lämpar sig olika väl i olika situationer:
- Nästling av
if-satser, dvsif-satser inne i andraif-satser. elif-klausuler.
Nästlade if-satser
if A:
# Code that runs if A evaluates to True.
else:
if B:
# Code that runs if A evaluates to
# False but B evaluates to True.
else:
# Code that runs if both A
# and B evaluate to False.
- Notera att den första klausulen inte påverkas av sanningsvärdet på
B.
Nästlade if-satser¶
- Syntax:
if A:
# Code that runs if A evaluates to True
else:
if B:
# Code that runs if A evaluates to False but B evaluates to True
else:
# Code that runs if both A and B evaluate to False
- Notera att den första klausulen inte påverkas av sanningsvärdet på
B.
Nästlade if-satser för vårt exempel¶
In [33]:
def get_price(rider_age):
if rider_age < 12:
return 0
else:
if rider_age < 18:
return 20
else:
if rider_age < 65:
return 30
else:
return 15
In [34]:
print(get_price(15))
20
- Fungerar men är förvirrande, ganska svårläst, och leder till djupare indentering ju fler fall vi har.
- Ibland är logiken sådan att nästling är tydligare, men inte i så här enkla fall.
elif-klausulen¶
- Syntaktiskt socker för nästlingen vi just såg.
- Utökar
if-satser med flera klausuler med olika villkor (men fortfarande bara en som körs). - Fått namn av att det rent logiskt är som att ha en ny
if-sats ielse-klausulen. - Syntax:
if A:
# Code that runs if A evaluates to True
elif B:
# Code that runs if A evaluates to False but B evaluates to True
else:
# Code that runs if both A and B evaluate to False
- Notera att den första klausulen inte heller här påverkas av sanningsvärdet på
B.
elif-klausuler för vårt exempel¶
In [35]:
def get_price(rider_age):
if rider_age < 12:
return 0
elif rider_age < 18:
return 20
elif rider_age < 65:
return 30
else:
return 15
In [36]:
print(get_price(12))
20
Logiska operatorer¶
- Logiska operatorer används för att kombinera eller negera sanningsvärden.
- Uttryck med logisk operator beräknas alltid till ett sanningsvärde, dvs antingen
TrueellerFalse.and:Trueom båda operander är sannaor:Trueom minst en av operanderna är sannanot:Trueom operanden ärFalse,Falseom operanden ärTrue
- Exempel
sensor1 > 100 and sensor2 <= 10
Exempel, vädret¶
Exempel, vädret¶
- Notera att vi inte har några
elif- ellerelse-klausuler nedan, så vi har 3 oberoendeif-satser med 1 klausul vardera.- (Dvs. mer än en av utskrifterna kan ske.)
In [37]:
def tell_me_about_the_weather(temp, precipitation):
if temp < 0 and precipitation:
print("I think it's snowing.")
if temp < 0 and not precipitation:
print("At least it's not snowing.")
if temp < -100 or temp > 100:
print("I think something is very wrong.")
In [38]:
tell_me_about_the_weather(-6.2, False)
At least it's not snowing.
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ärdensys: 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 nyckelordetimport. - Standard är att lägga alla importsatser i början av textfilen.
In [39]:
import random
- Funktionen
randinti modulenrandomger ett slumpmässigt heltal på ett slutet intervall mellan två givna heltal
In [40]:
print(random.randint(1, 3))
print(random.randint(1, 3))
print(random.randint(1, 3))
3 3 2
- Funktionen
randomi modulenrandom(ja, samma namn) ger ett slumpmässigt flyttal på det öppna intervallet $]0,1[$
In [41]:
random_float = random.random()
print(random_float)
0.5015541203533695
Import, namnrymder, punktnotation¶
import random- Ovanstående laddar in innehållet i modulen
randomoch ser till att det hamnar i namnrymdenrandom - Funktionen
randint(heltal1, heltal2)i modulenrandomkommer man då åt genom att skriva
random.randint(heltal1, heltal2)
In [42]:
# import-exempel 1
import random
list_of_names = ["Ada", "Bea", "Cecilia", "Dolores"]
def random_greeting1(names):
# random.choice() chooses a random element from a sequence
name = random.choice(names)
print("Hello " + name + "!")
def random_greeting2(names):
# random.randint() randomly returns
random_index = random.randint(0, len(names)-1)
print("Hello " + names[random_index] + "!")
In [43]:
random_greeting1(list_of_names)
Hello Dolores!
In [44]:
random_greeting2(list_of_names)
Hello Bea!
In [45]:
from random import choice, randint
# imports only choice and randint from random, but make them available in the global namespace, meaning we don't need the `random` prefix to actually use them
list_of_names = ["Ada", "Bea", "Cecilia", "Dolores"]
def random_greeting1(names):
name = choice(names)
print("Hello " + name + "!")
def random_greeting2(names):
random_index = randint(0, len(names)-1)
print("Hello " + names[random_index] + "!")
In [46]:
random_greeting1(list_of_names)
Hello Ada!
In [47]:
random_greeting2(list_of_names)
Hello Cecilia!