TDDE54
TDDE54 > Ada till Python
Göm menyn

TDDE54 Programmering och problemlösning

Ada till Python

Ada till Python, lathund

För att förenkla övergången från Ada till Python följer här nedan några exempel på hur vissa saker ser ut i Ada samt hur de ser ut i Python.

Hur man kör programmet

I Ada använder vi kompilatorn gnatmake för att skapa ett körbart program av vår källkod. Vi får då, om vi inte ger direktiv till kompilatorn, ett program som heter samma sak som filen vi kompilerar (den som innehåller huvudprogrammet). I terminalen kör vi:


gnatmake mitt_program.adb
./mitt_program

Python är inte ett kompilerat språk, utan interpreterat. Vi har alltså ingen kompilator. Nu får vi istället skicka programmet till en interpretator som hanterar motsvarigheten till kompilering och körning av programmet. Ett sätt att köra Pythonprogram i terminal är:


python3 mitt_program.py

Huvudprogram

I Ada har vi ett skelett för hur ett huvudprogram ska se ut. Följer vi inte det kan vi inte kompilera vårt program:


-- with / use diverse bibliotek
procedure Huvudprogram is
    -- Deklaration av typer
    -- Deklaration av underprogram
    -- Deklaration av variabler, samt eventuellt initiering.
begin
    -- satser
end Huvudprogram;

Alla satser vi skriver mellan begin och end kommer att kompileras och göras till ett program. Skriver vi satser efter end eller innan begin (utom deklarationer) så kommer programmet inte att kompilera.

I Python kan vi bara börja skriva koden rakt upp och ner i vår källkodsfil. Alla satser vi skriver kommer att interpreteras och köras. Vi har alltså inget "kodskelett" som vi måste följa. Däremot har vi i denna kurs två rader vi vill att ni kopierar och lägger in högst upp i era kodfiler:


#!/usr/bin/python3
# -*- coding: utf-8; mode: python; -*-

VIKTIGT: Om du får felet invalid token av rättningssystemet, men ditt program fungerar att köra när du själv testar det har det med dessa rader att göra. Antingen har du inledande blanktecken, eller inte kopierat hela.

Dessa två rader, för de som är nyfikna, har följande funktionalitet:

  • Den första gör så att programmet kan göras körbart, vi säger helt enkelt till datorn vilken version av Python vi vill köra, och var den finns.
  • Den andra raden deklarerar hur vi vill att tecknen ska hanteras, vilken typ av teckenkodning den ska följa. I detta fall säger vi till Python att teckenkodningen utf-8 ska användas under programmets körning.

Ni behöver absolut inte kunna detta utantill, eller ens komma ihåg vad de betyder, men vi vill att ni kopierar in dem i samtliga av era laborationsfiler.

I övrigt vill vi att ni håller er till en genomtänkt struktur, precis som i Ada. Era källkodsfiler bör ha ungefär denna disposition:


#!/usr/bin/python3
# -*- coding: utf-8; mode: python; -*-

# import av eventuella bibliotek
# Deklarationer av underprogram

# Variabler för huvudprogrammet i den mån det är möjligt att deklarera dem i förväg
# Satser    

Variabeldeklaration och tilldelning

I Ada kan vi bara deklarera variabler innan Begin för ett givet underprogram eller huvudprogrammet. Vi kan samtidigt tilldela värden under deklarationen med tilldelningsoperatorn :=.

I : Integer := 5;

I Python kan vi deklarera variabler var som helst i koden, och det räcker med att skriva ett variabelnamn och tilldela ett värde. Det kan vara mycket problematiskt: Om vi råkar stava fel på en variabel skapar vi helt enkelt en ny. Det är alltså extremt viktigt att vara noggrann när vi gör tilldelningar i Python, vilket vi gör med tilldelningsoperatorn =.


i = 5

Ovan har vi skapat en variabel (om den inte fanns tidigare) som kallas "i", och satt värdet till 5. Observera att Python gör skillnad mellan stora och små bokstäver:


I = "hej"
i = 5
print(i) # ger utskriften 5
print(I) # ger utskriften hej

Kommentarer

Ibland kan det vara lämpligt att lämna kommentarer i kod för att förtydliga ett avsnitt / block, eller för att kommentera bort enskilda rader vid testning. I Ada gjorde vi det på följande vis:


-- Denna rad är en kommentar, och kommer inte att kompileras.

I Python fungerar kommentarer likadant, men skrivs med annan syntax:


# Denna rad är en kommentar, och kommer inte att interpreteras.

In- och utmatning (IO)

I Ada har vi stor kontroll över de data vi hämtar från användaren. Det finns även olika "utskriftsunderprogram" (Put) för olika datatyper. Även för de inbyggda. Ex:


-- Vi vill ha tillgång till att skriva ut "rå text" (String, Character).
with Ada.Text_IO; use Ada.Text_IO; 

-- Vi kan nu använda oss av Put och Get för strängar och tecken:
    S : String(1..5);
    C : Character;
begin 
    Put("Hej!");
    New_Line; -- Vi gör ett radbryt i utskriften
    Put("Mata in ett tecken: ");
    Get(C); -- Vi hämtar ett tecken från inmatningsbufferten

Vi kan jobba på ungefär samma sätt med andra datatyper, men för att få åtkomst till rätt Put och Get behöver vi inkludera passande bibliotek. Ex: Vi vill jobba med strängar och heltal:


-- Vi vill ha tillgång till att skriva ut "rå text" (String, Character).
with Ada.Text_IO;         use Ada.Text_IO; 
-- Vi vill även skriva ut och hämta heltal:
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;

procedure HP is
-- Vi kan nu använda oss av Put och Get för strängar, tecken och heltal:
    S : String(1..5)
    I : Integer;
begin 
    Put("Hej!");
    New_Line; -- Vi gör ett radbryt i utskriften
    Put("Mata in ett heltal: ");
    Get(I); -- Vi hämtar ett heltal från inmatningsbufferten.
    Put("Du matade in heltalet: ");
    Put(I, Width => 0); -- Vi skriver ut heltalet med minimibredd 0.
    New_Line; 

I Python har vi inte riktigt samma kontroll vid inmatning, då Python i princip är typlöst på ytan. Exempel på inmatning:


print("Mata in ett heltal: ", end = "")
# print gör normalt "New_Line" automatiskt, genom att säga ', end = ""' säger vi att vi inte vill det.
i = input() # Vi läser in "något" från inmatningsbufferten, kanske ett heltal.
# Alternativt:
i = input("Mata in ett heltal: ") # Get samma resultat som de två raderna ovan
# Observera att oavsett vilken typ av data vi matar in kommer det att lagras som "string",
# vill vi använda det som något annat måste vi "casta" om det till den typ vi har tänkt oss.

Utskrifter och utskriftsformatering har vi dock gott om kontroll över.


i = 5 # Vi har en variabel "i" som får värdet 5 (heltal). Vi låtsas att det är ett godtyckligt
# inmatat värde för exemplen nedan.

# Vi vill skriva ut "Du matade in talet: " följt av talet, och nyrad.
# Detta kan vi göra på några olika sätt:
# Alternativ 1:
print("Du matade in talet: ", end = "")
print(i)

# Alternativ 2:
# Obs! När vi lägger till en variabel på detta vis, med kommatecken, skrivs ett mellanslag ut innan.
# Detta ger alltså samma utskrift som ovan.
print("Du matade in talet:", i)

# Alternativ 3:
# Vi "castar" om heltalet till en sträng och slår ihop strängarna:
print("Du matade in talet: " + str(i))

# Alternativ 4:
# Vi använder utskriftsformatering:
# print("Du matade in talet: {}".format(i))

# {} innebär att vi "håller en plats" åt något som vi skickar med
# till format. Vi kan här ge en mängd olika direktiv.

# Det finns andra alternativ, men vi håller oss till dessa i denna kurs.

Utskriftsformatering

Som vi nämner ovan kan vi formatera våra utskrifter ganska mycket med .format för strängar. Se några exempel nedan som jämför med Ada.


    I : Integer := 5;
    F : Float := 3.14;
begin
    -- Vi skriver ut ett heltal högerjusterat med minimibredd 10, om talet är mindre än
    -- 10 siffror fyller vi ut med mellanslag till vänster.	
    Put(I, Width => 10); 
    -- Vi vill nu skriva ut ett flyttal i decimalform, med 3 decimalers precision och
    -- med minimalt 5 tecken innan decimalpunkten. Extra utrymme innan decimalpunkten
    -- (färre värdesiffror än 5) fyller vi ut med mellanslag.
    Put(F, Fore => 5, Aft => 3, Exp => 0);

Vi kan göra motsvara med format i Python. Om vi använder oss av {} kan vi inom måsvingarna specificera dels vilken typ av data det är vi vill skriva ut, dels hur det ska formateras. För att göra identiska utskrifter som ovan kan vi göra:


i = 5
f = 3.14
# Vi skriver ut ett heltal högerjusterat med minimibredd 10, om talet är mindre än
# 10 siffror fyller vi ut med mellanslag till vänster.
# 10 står för 10 bredd, d står för decimal integer (heltal)
# Observera att programmet kraschar om variabeln innehåller något annat än ett heltal.
print("{:10d}".format(i))

# Vi vill nu skriva ut ett flyttal i decimalform, med 3 decimalers precision och
# med totalt 9 teckens bredd. Extra utrymme fylls upp till vänster med mellanslag.
# 9 nedan står för totala bredden, 3 efter punkt står för decimalprecision, och f
# står för float (flyttal).
print("{:9.3f}".format(f))

# Måsvinge-platshållarna kan stoppas in var som helst i en sträng, vi kan även ha flera
# i ett enda anrop. Här avgör parametrarnas ordning till format vilken som hamnar var.
# i står först, alltså kommer den hamna i första måsvingeparet, f står på andra plats och
# hamnar således i andra paret. Osv. om vi har fler. 
print("Ett heltal: {:5i} och ett flyttal: {:5.2f}".format(i, f))

Det finns denna typ av formateringstaggar för alla de grundläggande typerna ni är vana vid (och många andra). I Python hanteras character bara som om det är en synnerligen kort sträng, så vi använder oss av strängformatering om vi vill skriva ut characters formaterat. Observera att programmet kraschar om vi skickar data av felaktig typ till denna typ av formateringsstaggar.

  • Heltal (Integer): {:d}
  • Flyttal (Float): {:f}
  • Strängar (String): {:s}

If-satser

Inom programmeringen använder vi i synnerhet if-satser för att göra vägval i våra program. I Ada skrivs de på följande vis:


if Some_Condition then
-- Satser;
end if;

I Ada kommer alla satser som är mellan then och end if; att tillhöra if-satsen.

I Python fungerar if-satser på samma sätt, men syntaxen ser annorlunda ut:


if some_condition:
    # sats1
    # sats2
    # ...
# Ej i if-satsen. Här är if-satsen avslutad eftersom vi har slutat
# indentera satserna.

Viktigt! Observera att vi i Python inte har "then" som påbörjar if-satsen eller "end if;" som avslutar den, utan det är indenteringen som avgör vad som ingår i if-satsen och när den är avslutad.

Repetitionssatser (loopar)

I Ada har vi tre olika typer av loopar. For-loopen (när vi kan räkna ut hur många steg vi kan ta), while-loopen (när vi vill göra något från 0 till och med godtyckligt antal, så länge ett kriterie uppfylls), och sist men inte minst "loop-loopen" (minst en gång, i övrigt samma tanke some while-loopen). Vi skriver dem på följande vis:


-- For-loopen:
for I in 1..10 loop -- Räknar 1 till 10
    -- Satser;
end loop;

-- while-loopen
while Some_Condition loop
    -- Satser;
end loop;

-- loop-loopen
loop
    -- Satser;
    exit when Some_Condition;
end loop;

I Ada kommer alla satser som står mellan loop och end loop; att tillhöra loopen.

I Python har vi bara två olika loop-typer, for-loopen och while loopen. Vi kan ungefärligen återskapa loop-loopen, vilket vi visar nedan. I Python har looparn följande syntax:


# For-loopen
for i in range(1, 11): # Räknar 1 till 10.
    # satser
# Slut på loopen när vi slutar indentera satserna.

# While-loopen
while some_condition:
    # satser
# Slut på loopen när vi slutar indentera satserna.

# Motsvarigheten till Ada's loop-loop.
while True:
    # satser
    if some_sondition:
        break
# Slut på loopen när vi slutar indentera satserna.

Viktigt! Observera att vi i Python inte har "loop" som startar loopen eller "end loop;" för att avsluta den, utan det är indenteringen som avgör vad som ingår i loopen och när den är avslutad.

Operatorer

I Ada har vi använt ett helt gäng olika operatorer, för aritmetiska operationer, jämförelser, tilldelningar, osv. De skiljer sig lite grann i många fall mellan Ada och Python. Nedan följer listor på de vanligaste, och exempel på hur de fungerar:

Aritmetiska operatorer

I Ada har vi enkla aritmetiska operatorer:

I := I + 1; -- Vi använder "+"-operatorn för plus.
I := I - 1; -- Vi använder "-"-operatorn för minus.
I := I * 2; -- Vi använder "*"-operatorn för multiplikation.
I := I / 2; -- Vi använder "/"-operatorn för division. I Ada är resultatet ett heltal.
I := I mod 2; -- Vi använder "mod"-operatorn för modulo-räkning.

I Python ser de grundläggande operatorerna ungefär samma, frånsett modulo-operatorn:


i = i + 1 # Vi använder "+"-operatorn för plus.
i = i - 1 # Vi använder "-"-operatorn för minus.
i = i * 2 # Vi använder "*"-operatorn för multiplikation.
i = i / 2 # Vi använder "/"-operatorn för division. I Python är resultatet ett flyttal.
i = i // 2 # Vi använder "//"-operatorn för heltalsdivision. Resultatet blir ett heltal.
i = i % 2 # Vi använder "%"-operatorn för modulo-räkning.

Just nu tycker ni säker att det är ganska lika, men som extra bonus finns det i Python kombinationsoperatorer. De kombinerar tilldelning med en aritmetisk operator. I denna kurs vill vi inte att ni använder er av dessa. Vi vill, i introduktionskurser, premiera tydlig kod över kort eller effektiv kod i de fall de inte är samma sak. Det kan dock vara nyttigt att ha sett dem så att ni vet vad de är, och kan använda dem i framtida kurser.

Satserna nedan motsvarar Python-satserna ovan:


i += 1 # Vi använder "+="-operatorn för att förenkla "i = i + 1".
i -= 1 # Vi använder "-="-operatorn för att förenkla "i = i - 1".
i *= 2 # Vi använder "*="-operatorn för att förenkla "i = i * 2".
i /= 2 # Vi använder "/="-operatorn för att förenkla "i = i / 2".
i %= 2 # Vi använder "%="-operatorn för att förenkla "i = i % 2".

Jämförelseoperatorer

I programmering använder vi ofta jämförelseoperatorer för att jämföra värden. I Ada använde vi följande operatorer:

if I < 5 then -- Om I är mindre än 5
if I > 5 then -- Om I är större än 5
if I = 5 then -- Om I är lika med 5
if I /= 5 then -- Om I inte är lika med 5  
if I <= 5 then -- Om I är mindre än eller lika med 5
if I >= 5 then -- Om I är större än eller lika med 5

I Python ser operatorerna liknande ut, frånsett jämförelse-operatorn. Ada's likhetsoperator är tilldelningsoperator i Python.


if i < 5: # Om i är mindre än 5
if i > 5: # Om i är större än 5
if i == 5: # Om i är lika med 5
if i != 5: # Om i inte är lika med 5  
if i <= 5: # Om i är mindre än eller lika med 5
if i >= 5: # Om i är större än eller lika med 5

Viktigt! Var extra noga med att du noterar likhetsoperatorn. Adas "="-operator för likhet är tilldelningsoperator i Python.

Logiska operatorer

I Ada har vi mycket god kontroll över anropsordning och hur vi vill utvärdera enkla booleska uttryck. Vi har operatorerna and, or, and then, or else samt not:


with Ada.Text_IO; use Ada.Text_IO;

procedure Ada_Logic_Op is
   
   ----------------------------------------
   --     Returnerar sant och gör en     --
   --    utskrift för att visa hur de    --
   --    logiska operatorerna påverkar   --
   --            exekveringen            --
   ----------------------------------------
   function One return Boolean is
   begin
      Put_Line("One");
      return True;
   end One;
   
   ----------------------------------------
   --    Returnerar falskt och gör en    --
   --    utskrift för att visa hur de    --
   --    logiska operatorerna påverkar   --
   --            exekveringen            --
   ----------------------------------------
   function Two return Boolean is
   begin
      Put_Line("Two");
      return False;
   end Two;
     
begin
   -- And
   -- I detta uttryck får vi utskrifterna: Two, One, trots att vi vet
   --  att uttrycket är falskt redan efter "Two". Båda kriterierna
   --  kommer att exekveras oavsett utfall.
   if Two and One then
      Put_Line("If-statement passed");
   end if;
   
   -- And then
   -- I detta uttryck får vi utskriften: Two då det första kriteriet är
   --  falskt. Det andra kriteriet kommer bara att exekveras om det
   --  första är sant.
   if Two and then One then
      Put_Line("If-statement passed");
   end if;
   
   -- Or
   -- I detta uttryck får vi utskrifterna: One, Two, If-statement passed.
   --  Trots att One är sant, vilket uppfyller if-satsen, kommer vi
   --  att exekvera Two också. Båda kriterierna exekveras oavsett
   --  utfall.
   if One or Two then
      Put_Line("If-statement passed");
   end if;
   
   -- Or else
   -- I detta uttryck får vi utskrifterna: One, If-statement passed. Då
   --  det första kriteriet är sant vill vi inte exekvera det andra.
   --  Det andra kriteriet exekveras bara om det första är falskt.
   if One or else Two then
      Put_Line("If-statement passed");
   end if;

   -- Not
   -- I detta uttryck får vi utskrifterna Two, If-statement passed.
   -- Vi negerar ett booleskt uttryck med "not". Alltså uppfyller vi 
   -- if-satsen då Two returnerar "falskt". "Icke falskt" är "sant". 
   if not Two then
      Put_Line("If-statement passed");
   end if;


end Ada_Logic_Op;

I Python har vi inte samma kontroll, utan får nöja oss med and och or för att utvärdera enkla booleska uttryck:


########################################
##     Returnerar sant och gör en     ##
##    utskrift för att visa hur de    ##
##    logiska operatorerna påverkar   ##
##            exekveringen            ##
########################################
def one():
    print("One")
    return True

########################################
##    Returnerar falskt och gör en    ##
##    utskrift för att visa hur de    ##
##    logiska operatorerna påverkar   ##
##            exekveringen            ##
########################################

def two():
    print("Two")
    return False

# And
# I detta uttryck får vi utskriften: Two då det första kriteriet är
# falskt, och vi behöver inte utvärdera det andra kriteriet.  Det
# andra kriteriet kommer bara att exekveras om det första är sant.
if two() and one():
    print("If-statement passed")

# I detta uttryck får vi utskrifterna: One, Two då vi måste utvärdera
# det andra kriteriet eftersom det första är sant.
if one() and two():
    print("If-statement passed")

# Or
# I detta uttryck får vi utskrifterna: One, If-statement passed då det
# första kriteriet är sant, och vi behöver inte utvärdera det andra
# kriteriet. Det andra kriteriet kommer bara att exekveras om det
# första är falskt.
if one() or two():
    print("If-statement passed")

# I detta uttryck får vi utskrifterna: One, Two, If-statement passed
# då det första kriteriet är falskt, medan det andra är sant.
if two() or one():
    print("If-statement passed")

# Not
# I detta uttryck får vi utskrifterna: Two, If-statement passed.
# Vi negerar ett booleskt uttryck med "not". Alltså uppfyller vi 
# if-satsen då two returnerar "falskt". "Icke falskt" är "sant".
if not two():
    print("If-statement passed")

Vi kan dra följande slutsatser:

  • and i Python är ekvivalent med Ada's and then
  • or i Python är ekvivalent med Ada's or else

Underprogram

I Ada har vi tre olika typer av underprogram vi kan definiera själva:

  • Procedur: In/out parametrar, ingen return.
  • Funktion: Bara in parametrar, retur av exakt ett värde.
  • Operator: Lik funktion, men tar exakt två parametrar och anropas operand "operator" operand.
  • Exempel på hur de ser ut i Ada:
    
    -- Procedur      
    Procedure My_Print(S : in String) is
    
    begin
        Put("This is the very fancy print of a string containing: ");
        Put_Line(S);
    end My_Print;
    
    -- Funktion
    Function Plus_One(I : in Integer) return Integer is
    
    begin
        return I + 1;
    end Plus_One;
    
    -- Operator
    Function "-"(lhs : in Integer,
                 rhs : in Float) return Float is
    
    begin
        return 3.14;
    end "-";
    

    I Python har vi bara en enda typ av underprogram, men vi kan nyttja dessa som om de var en procedur eller funktion. Det innebär att vi bör vara än mer noga när vi gör våra underprogram, språket ser inte längre till att vi gör rätt. Operatorer kan vi, i scopet för denna kurs, inte skapa eller påverka.

    
    # Procedur. Vi har ingen returtyp deklarerad (eller None enligt
    # nedan), och vi kör inga return-satser.
    
    def my_print(s : str) -> None:
        print("This is the very fancy print of a string containing: {:s}".format(s))
    
    # Funktion. Vi deklarerar vilken typ av data vi tänker oss att
    funktionen ska returnera, och vi skickar ut data med return-satsen.
    
    def plus_one(i : int) -> int:
        return i + 1
    

    Några viktiga punkter:

    • I Python garanterar vi inte att vi gör rätt genom att deklarera typer på våra parametrar och underprogram. Vi förtydligar bara hur vi har tänkt oss att underprogrammet ska användas. Detta är ett krav i kursen.
    • Vi vill, precis som vi ville i Ada, deklarera en parameter per rad.
    • I vissa fall kan vi vilja skriva underprogram som tar parametrar av godtycklig typ. Då lämnar vi dem utan att deklarera typ. Det innebär att vi måste typdeklarera samtliga parametrar för sig, även om de ska ha samma typ.
      Ex:
      def my_function(i : int,
      	         j : int) -> int:


Sidansvarig: Viktor Olsson
Senast uppdaterad: 2021-11-10