6. Moment06 - Moduler och paket

Moduler, paket och bibliotek i python har alla gemensamt att de hänvisar till saker som måste importeras till din applikation för att kunna användas. En modul i python har du redan tillverkat själv i bankapplikationen i moment05. Modulen du tillverkade hette i tutorialen "functions.py". En modul är helt enkelt en fil som bara innehåller funktioner.

Eftersom moduler är något som vi redan arbetat med och även tillverkat själva är det paket och några olika externa sådana vi kommer titta på i moment06. Ett paket, även kallat bibliotek, är en samling moduler som ökar funktionaliteten i python. Ett paket du använt sedan du första gången använde python är "python standard library", som är ett standardpaket i python som tillåter dig att använda alla de funktioner och datatyper vi använt hittills.

I moment06 kommer du få studera några olika paket och moduler för att få en känsla av den breda funktionalitet som python erbjuder oavsett om du vill tillverka spel, göra vetenskapliga matematiska analyser eller något däremellan.

Info

Till detta moment finns en sida med lösningsförslag och videoklipp.

6.1 Använda paket i PyCharm

När vi arbetar i PyCharm och vill använda ett paket eller en modul som inte ingår i pythons standardbibliotek måste vi genomgå följande steg:

  1. Uppe i statusbaren (på mac), tryck på PyCharm -> Preferences... Klicka för bild
  2. Klicka på Project: dittProjektNamn Klicka för bild
  3. För att söka upp och installera nya paket och moduler, klicka på "+" nere till vänster i rutan. Sök sedan upp paket du vill installera och klicka på "Install package". Klicka för bild

6.2 SciPy

SciPy (scipy.org) är både ett samlingsnamn för en grupp python-paket som tillsammans är användbara i naturvetenskapliga syften och ett specifikt python-paket som heter just SciPy.

6.2.1 NumPy

Ett paket som ingår i SciPy är paketet NumPy. NumPy innehåller bland annat funktionalitet för att smidigare arbeta med listor, som här kallas för array (engelska för matris), funktionalitet för att skapa och arbeta med polynom och en massa annat vars syfte är att ge matematiker och naturvetare verktyg för att arbeta effektivt i python.

Kodexempel: Importera numpy enligt gällande standard

# Följande är det rekommenderade sättet att importera numpy
import numpy as np

6.2.1.1 Polynom

I matematik 2c lär du dig vad ett polynom är. Som en kort repetition så är ett polynom ett algebraiskt uttryck som består av både variabler och konstanter. Polynom kan ha flera dimensioner och dimensionerna i polynom avgörs av hur många olika variabler som används. Varje använd variabel ökar dimensionen med ett.

Polynom repetition [klicka för att visa]

Här finns ett videoklipp från MatteCentrum där två polynom multipliceras.

Kodexempel: Koden för exemplet i videoklippet

import numpy as np

höjd = np.poly1d([2, -3])
bas = np.poly1d([1, 2])
area = bas * höjd

print("Arean kan tecknas:\n", area)

Exempel på några endimensionella polynom:

x² + 3x + 4
2y³ - 2y² + 5y
5x² - 3x + 5012

Med hjälp av poly1d som ingår i numpy-paketet kan vi skapa och arbeta med 1-dimensionella polynom i python.

Kodexempel: Konstruera polynom med poly1d.

import numpy as np

# Konstruerar de tre polynom i exemplet ovan med np.poly1d(lista)
polynom1 = np.poly1d([1, 3, 4])
polynom2 = np.poly1d([2, -2, 5, 0], variable='y')
polynom3 = np.poly1d([5, -3, 5012])

# Som du kan se i utskrifterna skrivs varje polynom ut på två rader,
# där den första raden används för exponenterna på variablerna.
print(polynom1, '\n')
print(polynom2, '\n')
print(polynom3)

Utskrift

   2
1 x + 3 x + 4

   3     2
2 y - 2 y + 5 y

   2
5 x - 3 x + 5012

När vi konstruerat polynom kan vi utföra beräkningar på dem, som att slå ihop polynom med hjälp av valfri räkneoperation och att få fram värden vid olika värden på variabeln.

Kodexempel: Arbeta med polynom.

import numpy as np

polynom1 = np.poly1d([1, 3, 4])
polynom2 = np.poly1d([1, 1, 2, 5, 0], variable='y')
polynom3 = np.poly1d([1, -3, 5012])

# Genomför diverse beräkningar med polynomen
poly_ad_13 = polynom1 + polynom3

# Det spelar ingen roll vilken variabel som används,
# när polynomen adderas behandlas det som samma variabel
poly_ad_12  = polynom1 + polynom2

poly_mult_1konst = polynom1 * 4
poly_mult_13 = polynom1 *  polynom3

print('Polynom 1:\n{}\n\nPolynom 2:\n{}\n\nPolynom 3:\n{}\n'.format(polynom1, polynom2, polynom3))
print('Addition av polynom 1 och 3 ger:\n{}\n'.format(poly_ad_13))
print('Addition av polynom 1 och 2 ger:\n{}\n'.format(poly_ad_12))
print('Multipliceras polynom 1 med en konstant  4 får vi:\n{}\n'.format(poly_mult_1konst))
print('Multiplikation av polynom 1 och 3 ger:\n{}\n'.format(poly_mult_13))

Utskrift

Polynom 1:
   2
1 x + 3 x + 4

Polynom 2:
   4     3     2
1 y + 1 y + 2 y + 5 y

Polynom 3:
   2
1 x - 3 x + 5012

Addition av polynom 1 och 3 ger:
   2
2 x + 5016

Addition av polynom 1 och 2 ger:
   4     3     2
1 x + 1 x + 3 x + 8 x + 4

Multipliceras polynom 1 med en konstant  4 får vi:
   2
4 x + 12 x + 16

Multiplikation av polynom 1 och 3 ger:
   4        2
1 x + 5007 x + 1.502e+04 x + 2.005e+04

Några saker att tänka på vid hantering och särskilt vid utskrifter av polynom:

  • Varje polynom tar upp 2 rader, vilket innebär att vi är tvungna att skriva ut polynom på tomma rader för att det inte ska se konstigt ut.
  • Det spelar ingen roll vilken variabel som används när vi konstruerar polynom, när vi räknar med polynom tolkar numpy det som samma variabel.
  • Numpy använder vetenskaplig notation för stora tal. Till exempel är 2.005e+04 = 2.005 * 104 = 20050

Uppgift: m06u01

Konstruera applikationen fusk_2000 som låter användaren konstruera fyra valfria polynom.

Applikationen ska sedan skriva ut de polynom som användaren har matat in samt detta polynom i kvadrat genom att anropa funktionen print_polynom, som är en funktion du själv konstruerat och som har en lista som inparameter.

Konstanterna användaren anger får bara vara heltal.

Hjälp: Planering [klicka för att visa]

Här är ett ypperligt tillfälle att bryta ner uppgiften i mindre delar. Det kan vara smart att använda sig av pseudokod, som sedan blir kommentarer, för att planera lösningen.

Lämpliga verktyg att använda är;

  • Loopar
  • Listor
  • Funktioner
  • Inmatning
  • Typkonvertering / try-except:

Hjälp: Förslag på utskrifter [klicka för att visa]

Förslag på inmatning

Förslag på inmatning

Utskriften

Förslag på utskrifter

6.2.1.2 Array

Med numpy kan vi också konstruera listor på lite annorlunda sätt än tidigare. I numpy kallas listor för array och i följande kodexempel kan du se några sätt att skapa listor på med lite olika finesser.

Kodexempel: Konstruera listor med numpy.

import numpy as np

# Skapar en array med 6 jämt utspridda värden från 0 till 2
a = np.linspace(0, 2, 6)

# Fungerar på samma sätt som när du skapar en vanlig lista i pythons standardbibliotek
b = np.array([0, 1, 5, 12, -15])

# Skapar en array med heltal från 0 till 10, likt range i standardbiblioteket
c = np.arange(10)

# Skapar en array med 10st 1:or
d = np.ones(10)

# Skapar en array med 10st 0:or
e = np.zeros(10)

# Skapar en array med 10st slumpade tal mellan 0 och 100
f = np.random.randint(0, 101, 10)

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

Utskrift

[0.  0.4 0.8 1.2 1.6 2. ]
[  0   1   5  12 -15]
[0 1 2 3 4 5 6 7 8 9]
[1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[35 28 27 74 98 55 62 68  6 33]

Uppgift: m06u02

Din kompis ber dig försöka gissa vilket tal hen tänker på, du får veta att det är ett tal mellan 1 och 100. Du börjar med en enkel algoritm och gissar först på 1, sedan på 2, sedan på 3 osv ända tills du kommer till det tal din kompis tänkte på. Detta är ett exempel på en sökalgoritm.

  1. Bygg en applikation som simulerar det som förklarades i texten ovan. Sökalgoritmen ska konstrueras som en funktion i din applikation.
  2. finns det något sätt att optimera sökalgoritmen? Försök komma på ett sätt att skapa en funktion som gör sökandet mer effektivt.
    Tips: Importera time-modulen och undersök hur lång tid de olika algoritmerna tar. Klicka för bild
  3. Studera algoritmen som beskrivs i wikipediaartikeln (den första under rubriken procedure). Är detta den algoritm du hittade i uppgift b? Om ja, bra jobbat! Om nej, försök implementera algoritmen i ditt program och jämför söktiden mellan algoritmen i uppgift a) och uppgift b).

Uppgift: m06u03

Detta är en uppgift som bäst görs i grupp om 2-4 elever. Studera följande kod och resultatet av körningen.

Er uppgift är nu att

  1. Fundera och se till att hela gruppen förstår vad som händer i alla delar i applikationen.
  2. Skriv en pseudokod och tillverka ett aktivitetsdiagram till applikationen.
  3. Som ni ser är körtiden på applikationen lång. Optimera sökalgoritmen som används för att kolla om ett tal finns i listan eller ej.

6.2.2 matplotlib.pyplot

När vi konstruerat ett polynom med hjälp av numpy kan det vara intressant att se hur polynomet ser ut grafiskt, genom att plotta.

Exempel: Grafen till 𝑦=3𝑥3+2𝑥2+𝑥+10

Koden för att producera den här bilden är på endast 8 rader. Med hjälp av biblioteket matplotlib och en modul som heter pyplot blir det med hjälp av python väldigt enkelt att konstruera en mängd olika diagram.

Kodexempel: Importera pyplot enligt gällande standard

from matplotlib import pyplot as plt

För att konstruera ett diagram likt det i exempelbilden behöver vi först konstruera en lista med x-värden, och en lista med y-värden. När vi sedan vill rita ut linjen tar python och studerar punkter på linjen som finns i listorna och anpassar sedan en linje.

Kodexempel: En enkel graf

# Importerar pyplot för att rita grafen
# och numpy för att konstruera polynom och lista med x-värden
import numpy as np
from matplotlib import pyplot as plt

# Konstruerar en lista med x-värden från 0 till 10
x = np.arange(0, 11)

# Konstruerar en lista med 10 slumptal mellan 0 och 10
y = np.random.randint(0, 11, 11)

# konstruerar grafen med plt.plot
plt.plot(x,y)

# Ser till att grafen inte stängs med plt.show om vi inte stänger fönstret
plt.show()

Utskrift

Kodexempel: Grafen till y=2x-3

import numpy as np
from matplotlib import pyplot as plt

# Konstruerar polynomet 2x - 3
y = np.poly1d([2, -3])

# Konstruerar en lista med heltal från 1 till 10 som våra x-värden
x = np.arange(-10, 11)

# poly1d kan ta in x-värden och konstruera en
plt.plot(x,y(x))
plt.show()

Utskrift

Uppgift: m06u04

Konstruera en applikation som ritar ut 10 olika polynom. Här har du stor valfrihet hur applikationen är uppbyggd och får fria tyglar.

6.3 Turtle graphics: En del av pythons standardbibliotek

Turtle graphics (turtle) är en modul som ingår i pythons standardbibliotek och är en modul för att rita ut saker i ett fönster på skärmen. Eftersom turtle ingår i pythons standardbibliotek behöver vi inte installera något utan kan bara importera modulen på samma sätt som t.ex. math. När vi importerat turtle behöver definiera två variabler för klasserna Turtle och Screen och på sista raden i en fil som använder turtle-grafik måste vi skriva turtle.done().

Problem med namngivning

När du leker med Turtle så kan du inte skapa en fil som heter turtle.py för då kommer du få ett error när du skall köra din applikation. Orsaken till detta är att du då försöker importer din egna fil istället för att importera paketet turtle och då finns ju inte alla funktioner du behöver.

Kodexempel: Skapa ett fönster med Turtle

# Importerar turtle modulen
import turtle

# Definierar variablerna fönster och t som
# turtle.Screen() och turtle.Turtle()
fönster = turtle.Screen()
t = turtle.Turtle()

# Saknas detta kommando på sista raden kommer
# fönstret stängas när programmet är klart
turtle.done()

6.3.1 Screen

Klassen Screen kontrollerar ritfönster och genom att anropa den i början av applikationen kan vi ställa in fönsterstorlek och bakgrundsfärg.

Kodexempel: Ställa in ritfönstret

import turtle

fönster = turtle.Screen()

# Sätter bakgrundsfärgen till orange och storleken på fönstret till 800x800 pixlar
fönster.screensize(800, 800)
fönster.bgcolor('orange')

turtle.done()

I fönster.setup() anges först fönstrets bredd (x-led) följt av fönstrets höjd (y-led) och i fönster.bgcolor() anges antingen någon av de fördefinierade färgerna som exempelvis 'orange', 'black', 'pink', 'green' osv., men du kan också ange färger på några andra sätt som förklaras här.

6.3.2 Turtle

Klassen Turtle kan vi tänka på som en penna som kan rita diverse figurer genom att röra sig på skärmen. I uppgift m06u05 får du själv studera några olika funktioner till Turtle-klassen och förklara vad de gör.

På pythons hemsida finns mer information om paketet Turtle för den som vill lära sig mer om de olika funktionerna.

Uppgift: m06u05

Kopiera och kör koden och kommentera sedan vad varje rad gör.

import turtle
t = turtle.Turtle()
t.forward(100)
t.left(45)
t.backward(200)
t.right(90)
t.forward(350)
t.goto(-200, 200)
t.penup()
t.forward(50)
t.pendown()
t.color('red', 'green')
t.begin_fill()
t.circle(100)
t.end_fill()
t.forward(500)
turtle.done()

Hjälp [klicka för att visa]

I Turtles koordinationssystem så ligger origo (x=0, y=0) i mitten på fönstret. För den som jobbat med spelutveckling eller skapande av GUI tidigare så kan det verka märkligt.

Här finns ett kodexempel som använder sig av funktionerna pos(), xcor() och ycor() vilket gör att du kan fråga vilken position din turtle har.

import turtle

def print_turtleinfo(t):
    print("
Information om turtelns position")
    print("Pos():", t.pos())        # Anger position för din turtle (x, y)
    print("XCor():", t.xcor())      # Anger x-position för din turtle
    print("YCor():", t.ycor())      # Anger y-position för din turtle


# Origo i mitten på skärmen
t = turtle.Turtle()
print_turtleinfo(t)
t.goto(50, 50)              # Gå till koordidnat x:50, y:50
print_turtleinfo(t)
t.goto(100, 0)
print_turtleinfo(t)
t.goto(0, 0)
print_turtleinfo(t)
t.left(105)                 # Sväng vänster 105 grader
t.forward(100)              # Gå 100 steg (pixlar) framåt
print_turtleinfo(t)

turtle.done()

I m06u05 ser du att riktningen blir lite konstig i slutet. Vill vi kontrollera utgångsriktningen vår Turtle ska ha kan vi använda metoden setheading() där vi i parentesen anger en riktning i grader (0 - 360).

Uppgift: m06u06

  1. Konstruera en applikation som ritar ut en cirkel, en kvadrat, en rätvinklig triangel och en liksidig triangel. Figuererna får inte överlappa varandra och 2 av figurerna ska vara i fyllda med olika färger.
  2. Utvidga antalet figurer till 4 cirklar, 4 kvadrater, 7 rätvinkliga trianglar och 2 liksidiga trianglar.
    Här kan det vara bra att konstruera egna funktioner för de olika figurerna för att undvika upprepning i din kod.
  3. Konstruera en applikation som genererar en bild som är så lik bilden nedan som möjligt. Det är endast figurerna du ska härma. De svarta punkterna med text är för att visa koordinaterna i några delar av bilden som en hjälp för att kopian ska bli så nära originalet som möjligt.
    bild
    (Koordinaterna syns bättre om du zoomar in bilden)

6.3.3 Eventbaserad programmering

I turtle modulen kan vi låta olika funktioner köras baserat på knapptryckningar på tangentbord eller musklick på skärmen. En sådan händelse kallas för ett event och när vi skapar applikationer som beror på event får vi tänka om lite i strukturen. Eventbaserad programmering kan ses som att vi hela tiden har en loop som inväntar olika event från användaren. Vi ska inte gå in så mycket mer i eventbaserad programmering, men en inblick kan nog vara bra för att hänga med i exemplen när vi börjar styra vår sköldpadda med piltangenterna och muspekaren.

Vill vi styra vår sköldpadda med till exempel piltangenterna behöver vi ha en metod som dels säger åt sköldpaddan att göra något baserat på vilken tangent vi trycker på, men också en metod som säger till applikationen att kolla om användaren tryckt på någon knapp eller ej.

I turtle är metoden för att ritfönstret ska kolla om användaren tryckt på någon knapp eller klickat någonstans på skärmen listen(). När vi i koden implementerat listen måste vi ha någon metod som kopplar ihop ett visst knapptryck med en viss funktion. Metoden som används för detta är onkey() och i den måste vi ange ett funktionsnamn samt vilken knapptryckning som ska starta funktionen.

Tutorials

Här nedanför kommer jag först presentera två kortare kodexemepl på hur vi kan styra händelser i Turtle med tangentbord och musen. Sedan kommer jag lista ett antal tutorials som du kan följa för att bygga olika spel. Spelen visar på olika spellogik och om du senare vill bygga ett eget spel som slutprojekt så kan du behöva använda logik från flera av dessa tutorials. För varje tutorial försöker jag presentera vilken logik som används. Jag har också försökt lägga tutorals i svårighetsgrad med den enklaste först. Ingen bygger på någon annan men flera av dem innehåller samma typ av logik, tex. kollisionshantering.

När du letar efter egna tutorials så kommer du märka att många av dem bygger på objektorientering. Objektorientering kommer först i nästa kurs, så jag har valt att inte länka in sådana tutorials. Vill du följa en tutorial och jobba med objektorientering så är det ok, men eftersom det inte ingår i kursen så kommer det inte vägas in i bedömningen av ett betyg.

Kodexempel: enkelt styrsystem [klicka för att visa]

import turtle

# Setup
fönster = turtle.Screen()
seb = turtle.Turtle()
fönster.bgcolor('lightblue')
fönster.title('Flygande sköldpaddan')
seb.color('red')
seb.shape('turtle')
seb.turtlesize(5)
seb.penup()
seb.speed(5)


# Funktioner
def färdas():
    """Får sköldpaddan att hela tiden färdas framåt"""
    seb.forward(5)
    # Uppdaterar ritfönstret
    fönster.update()
    # Upprepar funktionen 1 gång per milisekund
    fönster.ontimer(färdas, 1)


def vänster():
    """Byter riktningen till vänster"""
    seb.setheading(180)


def höger():
    """Byter riktning till höger"""
    seb.setheading(0)


def upp():
    """Byter riktning till upp"""
    seb.setheading(90)


def ner():
    """Byter riktning till ner"""
    seb.setheading(270)


def avsluta():
    """Avslutar programmet"""
    fönster.bye()


# Ber ritfönster kolla efter specifika knapptryckningar
fönster.onkey(vänster, 'Left')
fönster.onkey(höger, 'Right')
fönster.onkey(upp, 'Up')
fönster.onkey(ner, 'Down')
fönster.onkey(avsluta, 'Escape')
fönster.listen()

# Anropar funktionen färdas
färdas()

# Det obligatoriska kommandot på sista raden i en turtleapplikation
turtle.done()

Kodexempel: Rita en slumpmässig kvadrat då vi trycker på mellanslag [klicka för att visa]

# nödvändiga importer
import random
import turtle

# Setup
fönster = turtle.Screen()
t = turtle.Turtle()
fönster.screensize(800, 800)
t.speed(0)


def slump_kvadrat():
    """Genererar en slumpmässig kvadrat i ritfönstet"""

    # Genererar slumpade x och y koordinater
    # och flyttar sköldpaddan dit
    x = random.randint(-400, 200)
    y = random.randint(-400, 200)
    t.penup()
    t.goto(x, y)
    t.pendown()

    # Genererar en slumpmässig sidstorlek och färger
    sida = random.randint(50, 200)
    r = random.random()
    g = random.random()
    b = random.random()
    t.color((r, g, b))

    # Ritar en kvadrat
    t.begin_fill()
    for i in range(4):
        t.forward(sida)
        t.left(90)
    t.end_fill()


# Anger att när funktionen slump_kvadrat körs när användaren trycker på mellanslag
fönster.onkey(slump_kvadrat, 'space')

# Säger till ritfönstret att lyssna efter event
fönster.listen()

# Det obligatoriska kommandot på sista raden i en turtleapplikation
turtle.done()

Kodexempel: Styra med musen [klicka för att visa]

Här följer två tutorials där du även kan använda musen för att påverka din turtle.

Styra musen med touchpad på en mac

I de tutorials som finns nedan så pratar han om tre musknappar. När du jobbar med touchpad som finns på en mac så används bara två knappar, vänster som aktiveras med onscreenclick(clickleft, 1) och höger som aktiveras med onscreenclick(clickright, 2).

Videotutorial: Kollisionshantering mot vägg [klicka för att visa]

När vi bygger spel så är det viktigt att saker kan kollidera, det gör vi för att både kunna hålla koll på att saker som rör sig finns kvar inne i skärmen men även för att kunna samla poäng eller förlora när vi träffar ett annat objekt.

Här kommer en tutorial i fyra delar där bollar studsar i en avgränsad yta.

Tutorial: A simple game [klicka för att visa]

A simple game

I denna tutorial så byggs ett enkelt spel upp där du kommer lära dig en hel del matnyttiga saker för att kunna bygga ett spel. Fokus i denna tutorial ligger på kollisionshantering, att kunna spela mot flera fiender.

Spelet är kodat i Python 2.7 men jag har kört igenom hela tutorialen och det enda som behöver ändras är sista raden där du skall byta ut delay = raw_input("Press Enter to finish.") mot turtle.done().

Ljud och bilder som används i slutet av tutorial hittar du här.

Tutorial: Space invaders [klicka för att visa]

Space invaders

En tutorial där det klassiska spelet Space Invaders återskapas. Här byggs spelet upp med grafik, ljud, olika typer av kollisioner, poängberäkning mm.

Spelet är kodat i Python 2.7 men jag har kört igenom hela tutorialen och det enda som behöver ändras är sista raden där du skall byta ut delay = raw_input("Press Enter to finish.") mot turtle.done().

Ljud och bilder som används i slutet av tutorial hittar du här.

Uppgift: m06u07

Här vill jag att du själv undersöker eller arbetar vidare med någon uppgift/kodexempel/tutorial som du har gjort här ovan. Exakt vad du vill göra avgör du själv.

  • Bygg vidare på ett av de spelen som du har jobbat med?
  • Bygg ihop delar av två spel till ett nytt?
  • Bygg ihop de två kodexemplen enkelt styrsystem och Rita en slumpmässig kvadrat för att skapa något nytt/annat.

Gör ett kommentarshuvud längst upp där du förklarar vad du lagt till för funktionalitet, varför du lade till den och förslag på ytterligare utveckling av applikationen.

6.4 PyGame

PyGame är den mesta använda spelmotorn för Python där du kan skapa egna spel. För de elever som tycker att det är intressant att jobba med Turtle och där påbörjar att bygga egna spel så är PyGame den naturliga fortsättningen för att göra mer avancerade spel.

I denna kursen kommer vi inte jobba specifikt med PyGame men för den som är intresserad så finns det en uppsjö av olika guider och tutorials för att bygga en mängd olika spel.

Den elev som vill testa PyGame och även göra ett slutprojekt med PyGame får på egen hand utforska detta bibliotek. Lite vaksamhet krävs dock, väldigt mycket av det material som finns bygger på objektorientering vilket är en teknik som ligger utanför denna kursen. Att använda objektorientering inom ramen för kursen är ok, men du kan inte höja ett betyg genom att göra det.