tisdag 5 februari 2013

Moduler och arv

Klasser och moduler

Det går utmärkt att ha flera klasser i en modul. Om du då vill komma åt dessa klasser från en annan modul importerar du modulen. Som för funktioner skriver du sedan modulnamn.Klassnamn när du vill använda klassen. Ex:

import minmodul

...

# Skapar objektet mittobjekt av klassen MinKlass från modulen minmodul
mittobjekt = minmodul.MinKlass()

...

Övning 2.25
Kopiera klasserna för de geometrikska kropparna du skapat till en modul med namnet klossar (filnamnet är alltså klossar.py).

Arv eller klasser och underklasser

En av poängerna med objektorienterad programmering är arv av egenskaper mellan klasser. Vi kan skapa en huvudklass med de variabler och metoder som objekt i underklasser skall ha gemensamt.

Vi vill att alla klossar skall ha en position och en färg. Positionen skall vara en  lista med tre element [x, y, z] och färgen en textsträng. Vi vill kunna ändra färg och också ha möjlighet att flytta klossarna genom att ange en ny position.

Huvudklassen blir då:

#Huvudklass Klossar
class Kloss :
    def __init__(self):
        self.position =[0, 0, 0]
        self.farg=""
        
    def flytta(self,position):
        self.position=position
        
    def satt_farg(self, farg):
        self.farg=farg
  

Nu har vi grunden för metoder och variabler som kan ärvas av alla varianter av klossar vi skapar. Metoderna i underklasserna går före de i huvudklassen så då det finns en metod volym() i klassen Kub så körs den om objektet är en kub. Skulle det inte finnas en metod i underklassen så körs istället den i huvudklassen.Så om man kallar på metoden flytta för en kub så körs metoden i huvudklassen Klossar.

För att göra det lite snyggt  så inför vi tomma metoder i huvudklassen för de som ska implementeras i alla underklasser, alltså volym, area och skala. Genom detta är det lätt att se vad en underklass förväntas implementera. Tomma metoder skapas genom att lägga in pass som enda del i metodkroppen. Metoden skala(k) i huvudklassen Klossar ser alltså ut så här:

    def skala(self, k):
        pass

Övning 2.26
Lägg till tomma klasser för skala, volym och area i huvudklassen


Att skapa arvet

Nu måste vi få underklasserna att ärva metoder och variabler från huvudklassen.

För att tala om att en klass är en underklass till en annan anges huvudklassen i parentes bakom namnet på underklassen. I vårt fall ändrar vi i raden där vi definierar Kub till:

class Kub(Kloss) :

Nu är Kub en underklass till Klossar och har tillgång till dess metoder.För att Kub skall få samma variabler som huvudklassen ser vi till att huvudklassens initiering körs samtidigt som underklassens. Detta sker med hjälp av funktionen super(). super(). refererar till huvudklassen ungefär som self refererar till klassen själv.

Klassen Kub får med arv och initiering av variablerna i Klossar utseendet:

class Kub(Kloss) :
    
    def __init__(self, sida):
        super().__init__()
        self.sida=sida
        
    def skala(self, k):
        self.sida=self.sida*k
           
    def volym(self):
        return self.sida*self.sida*self.sida
    
    def area(self):
        return self.sida*self.sida*6

Övning 2.27
Skriv om övriga kloss-klasser så att de ärver metoder och variablerna från Klossar.

Övning 2.28
Skapa en ny modul, klosstest, och pröva att arvet fungerar:
Skriv och kör:

import klossar

kuben=klossar.Kub(8)
print(kuben.position)
kuben.flytta([1,2,3])
print(kuben.position)
kuben.skala(2)
print(kuben.volym())

Övning 2.29
Skriv tester för några av de andra kloss-typerna samt färgen också.

måndag 4 februari 2013

Övningar klasser

Vi ska skapa några klasser för att testa hur de fungerar. Vi skapar klossar av olika slag.
  • Kub
  • Rätblock
  • Pyramid - kvadratisk bas och symetrisk
  • Cylinder
  • Klot
En klass blir en ritning till var och en av klosstyperna. Vi vill förutom att skapa klossen även kunna få reda på dess volym och begränsningsarea.

Vi kan skapa alla klasserna i samma modul. Här är klassen för Kuben:

class Kub :
    
    def __init__(self, sida):
        self.sida=sida
        
    def volym(self):
        return self.sida*self.sida*self.sida
    
    def area(self):
        return self.sida*self.sida*6

Övning 2.22
Skapa klasser för de övriga klosstyperna i samma modul (fil). Tips: tänk på vilka mått som måste anges för de olika typerna och undvik åäö.

Vi kan nu använda klasserna för att skapa objekt och utföra beräkningar med dessa. Till exempel ta reda på sammanlagda volymen av en kub med sidan 8 och ett klot med radien 4. I huvudprogrammet skriver vi:

kuben=Kub(8)
klotet=Klot(4)
print(kuben.volym()+klotet.volym())

Uppgift 2.7
Bestäm sammanlagda arean av dessa tre objekt:
En pyramid med bas-sidan 5 och höjden 10
Ett rätblock med längden 8, bredden 4 och höjden 6
En cylinder med radien 5 och höjden 6

En metod som ändrar objektet

Ovanstående objekt kan inte förändras efter att de skapats. Vi kan göra de mer användbara genom att införa metoder som ändrar objektet. Till exempel ändrar dess storlek genom skalning. Följande version av klassen Ratblock kan skalas upp eller ned med metoden skala(k) där k är skalfaktorn:

class Ratblock :
    
    def __init__(self, langd, bredd, hojd):
        self.langd=langd
        self.bredd=bredd
        self.hojd=hojd
    
    def skala(self, k):
        self.langd=self.langd*k
        self.bredd=self.bredd*k
        self.hojd=self.hojd*k
    
    def volym(self):
        return self.langd*self.bredd*self.hojd
    
    def area(self):
        return self.langd*self.hojd*2+self.bredd*self.hojd*2+self.bredd*self.langd*2

Övning 2.23
Lägg till skalningsmetoder för övriga klasser.

Övning 2.24
Hur mycket ändrar sig begräsningsarea och volym på en kub med sidan 4 som skalas upp 10 ggr.