Programmering grundkurs Föreläsning 9 Jody Foo, jody.foo@liu.se
Föreläsningsöversikt Repetition: klass, instans, objekt, instansvariabler, metoder Laboration 5 Klassdiagram med UML Undandtag - felhantering Programmeringsaktiviteten och att skriva kod Standarder för Python. PEP8 och PEP257. Funktionskommentarer och kommentarer för utvecklare Dela upp kod Omfaktorering av kod Testning och felsökning
Kort repetition
Terminologi Klass Objekt / Instans Egenskapsvariabel / Instansvariabel Metod
Objektorienterad programmering (OOP) En klass är en mall, en beskrivning (definition) av något som kan finnas när ett program körs. Det som finns i världen är instanser av klasser, även kallade för objekt. En klassdefinitioner används för att skapa ett objekt (instans av en klass) En klass beskriver vilka egenskaper (instansvariabler) dess instanser har och vilka beteenden (metoder) den har.
Instansvariabler och metodanrop class Book(object): def init (self, title): self.title = title self.author = "Unknown" self.year = "N/A" def str (self): citation = "{}. ({}). {}." return citation.format(self.author, self.year, self.title) bok1 = Book("The Practice of Computing using Python") bok2 = Book("PSwAaDSuP") print(bok1) print(bok2)
Laboration 5 Del 1: syntax för att skapa och använda klasser Del 2: använda objekt + öva på att skriva kommentarer, följa kodstandarder
Del 2 Kodskelett: random-layout.py Gränssnitt: lab5.py
random-layout.py #!/usr/bin/env python3 """Laboration 5 -- TDDE44 Exempel på slumpmässig layout-funktion. Layout-funktionen skickas som argument när en instans av lab5.layouttester skapas. """ # Läs denna fil för att se hur gränssnittet skapats. import lab5 import random def random_layout(squares, frame_height, frame_width): """Placera ut fyrkanterna i listan squares slumpmässigt. Argument: squares -- Lista som innehåller tkinter.label-objekt frame_height -- Höjden (int) på den Fram som fyrkanterna ligger i frame_width -- Bredden (int) på den Frame som fyrkanterna ligger i """ # Slumpa ut positioner för alla fyrkanter utan att de hamnar utanför framen for square in squares: square_size = square.winfo_width() xpos = random.randint(0, frame_width - square_size) ypos = random.randint(0, frame_height - square_size) square.place(x=xpos, y=ypos) if name == " main ": layout_tester = lab5.layouttester(random_layout, 600, 600)
Exempel på funktionsobjekt def print_hello(): print("hello World!") bacon = print_hello bacon() # utskrift # Hello World!
Demonstration
Klassdiagram i UML ett slags pseudokod för OOP
Klassdiagram i UML Unified Modelling Language Klassnamn namn : attributtyp namn : attributtyp = defaultvärde operation() operation() : returdatatyp operation(parameterlista) operation(parameterlista) : returdatatyp
Exempel DataRow trial : str image_file : str time : int correct_answer : str subjects_answer : str degrees_rotated : int get_error_type() : int
UML, klassdiagram: relationer mellan objekt Objekt kan ha någon form av relation till andra objekt association: allmän relation. kardinalitet (antal) och roll (i praktiken variabelnamn) "lästa_böcker 0..*"
UML: Relationer Yanpas. Wikimedia Commons En dubbelriktad association kan ritas utan pilar.
Exempel LayoutTester layout_func : callable squares_frame_height : int squares_frame_width : int size_options : list ui_xpadding : int ui_ypadding : int squares 0..* tkinter.tklabel winfo_width() : float place(x : float, y : float) init_ui() init_control_panel() create_size_panel() create_num_squares_panel() create_start_pos_panel() create_run_quit_panel() create_squares() clear_squares() run_layout()
Programmeringsmetod Undersökning och analys av problemet, felhantering, implementation, testning, felsökning
Namngivning Namngivning av klasser: substantiv i singular Namngivning av metoder: verb Namngivning av instansvariabler: substantiv OBS! Om klassen representerar en samling objekt, dvs fungerar som en behållare, använd inte beskrivning av innehållet. Ett vanligt mönster är att använda ett suffix, t.ex. Collection, Set eller List
Exempel på klassnamn DataPoint DataPointCollection Word Sentence Paragraph Document Person ContactList Book Library BookCollection
Vanliga prefix till metodnamn get_: hämta ett värde från ett objekt (antingen beräknat eller direkt från ett attribut) set_: sätt att värde (ändra hela) add_: lägg till ett värde remove_: ta bort ett värde load_: ladda data från fil save_: spara data till fil
Felhantering med undantag Exceptions
Exceptions - undantag Exceptions (sv undantag) är ett sätt att hantera fel i kod som kan utlösas (eng throw/raise). Vid fel kan ett undantag utlösas. Programmet avbryter sitt normala flöde för att gå in i "undantagsläge". Finns inget specificerat undantagsläge, kraschar programmet.
Undantag i Python Om man vill hantera undantag i Python lägger man koden som kan utlösa undantag i ett try-block. Undantag hanteras sedan i ett except-block.
Exempel på undantag i Python ZeroDivisionError IOError IndexError KeyError TypeError
Mönster för undandagshantering i Python try: # här lägger man koden som kan utlösa ett undantag except [typ av exception] [as <namn på undantagsinstans>]: # här lägger man koden för vad som ska hända Här ska inte hakparenteserna skrivas ut, utan visar att det som står innanför dem är valfritt. Det som står inom mindre än/större än-tecken måste vara med. I det här fallet bara om 'as' används. Mindre än/större än-tecknena ska inte heller stå med.
Exempel: Fånga undantag letters = ["a", "b", "c", "d", "e", "f"] try: l_index = 0 while True: print(letters[l_index]) l_index += 1 except: print("an exception was raised.")
Exempel: Fånga och instansiera undantag letters = ["a", "b", "c", "d", "e", "f"] try: l_index = 0 while True: print(letters[l_index]) l_index += 1 except Exception as error: print("an exception was raised.") print(error)
Exempel: Fånga specifikt undantag letters = ["a", "b", "c", "d", "e", "f"] try: l_index = 0 while True: print(letters[l_index]) l_index += 1 except IndexError: print("index " + str(l_index) + " is out of bounds.")
Exempel: Fånga och instansiera specifikt undantag letters = ["a", "b", "c", "d", "e", "f"] try: l_index = 0 while True: print(letters[l_index]) l_index += 1 except IndexError as index_error: print("index " + str(l_index) + " is out of bounds.") print(index_error)
Olika sätt att använda undantag För att fånga potentiella fel i koden och åtgärda dem Som ett alternativ till "vanlig" flödeskontroll/if-satser
Kontroll av argument med hjälp av flera undantag def get_dog_desc(dog_dict): try: output_string = "My name is " + dog_dict['name'] + " " output_string += "and I am " + str(dog_dict['age']) + " years old." return output_string except TypeError as type_error: print("argument not a dictionary") print(type_error) except KeyError as key_error: print("wrong keys in dictionary.") print(key_error)
Kontroll av argument med hjälp av flera undantag som ett fall def get_dog_desc(dog_dict): try: output_string = "My name is " + dog_dict['name'] + " " output_string += "and I am " + str(dog_dict['age']) + " years old." return output_string except (TypeError, KeyError) as error: print("not a dictionary or key not present in dictionary.") print(error)
Konsten att skriva bättre kod 1. kommentera 2. skriv kod 3. testa 4. rätta buggar 5. omfaktorera
Kommentarer och kodstandard
Kod- och kommentarsstandard Standard för att skriva pythonkod: PEP8 krav på att följa PEP8 fr.o.m. laboration 5 https://www.python.org/dev/peps/pep-0008/ Indentering: 4 mellanslag (rekommenderas) Radlängd: 79 tecken Rader bryts på rätt sätt med rekommenderad indentering Användning av tomma rader, mellanrum mellan operatorer etc. Variabelnamn, funktionsnamn, klassnamn
Kod- och kommentarsstandard Standard för att skriva pythonkommentarer: PEP257 krav på att följa från och med laboration 5 https://www.python.org/dev/peps/pep-0257/ Funktionskommentarer, "docstrings", för användaren Löpande kommentarer för utvecklaren Olika detaljnivå på funktionskommentarer och löpande kommentarer
Automatisk kontroll av PEP8 och PEP257 Aktivera virtuella miljön som har pycodestyle och pep257 installerade: source /courses/tdde44/kursmaterial/venv_pep/bin/activate PEP8: Använd kommandot pycodestyle PEP257: Använd kommandot pep257
Dela upp problem, bryta ut funktioner, abstraktion
Dela upp problem Vad är det övergripande problemet? Vilka delsteg finns? Finns det återkommande moment? Kan man skriva en funktion som utför det återkommande momentet? Använd "Dela upp problem" på varje delsteg
Dela upp funktioner/metoder Målet är att en funktion/metod gör en sak. Varför? det är lättare att köra flera funktioner/metoder i sekvens än att uttrycka "kör allt i funktionen X förrutom..." Man kan alltid anropa på andra funktioner/metoder från en annan funktion/metod
OOP och problemuppdelning OOP kombinerar: procedurell abstraktion - abstraktion av processer dataabstraktion - abstraktion av data
Omfaktorering
Omfaktorering, exempel Dela upp långa funktioner i mindre funktioner Förbättra variabelnamn Ändra på datastrukturer
Många olika sätt att lösa ett och samma problem Program som håller koll på när ett rum är bokat Exempel på funktionella lösningar en lista för varje rum. listan innehåller textsträng med bokad tid en gemensam lista med alla rum, listan innehåller listor med namn på rum, samt bokad tid Exempel på lösningar med OOP en klass som definierar ett rum med som innehåller en lista med bokade tider en klass som definierar en bokning med tidpunkt för bokningen en klass som definierar en bokning med tidpunkt för bokningen samt namn på rummet
Testning och felsökning
Att testa sin kod Testdriven programmering - utanför omfånget för denna kurs Vi använder spårutskrifter och pythons interaktiva läge. Vad borde funktionen/metoden returnera? Gör den det? Interaktivt läge: ipython3 -i <filnamn> Kommandon: ls, cd, cat etc fungerar %run <filnamn> - kör fil %reset - rensa minnet från användarens variabler Ctrl-D för att avsluta (Ctrl-D är även kontrolltecknet för EOT, End of Transmission)
Använda python interaktivt Anropa funktioner, skapa instanser av klasser från fil(er) som laddats in i minnet. Allt man kan göra från en textfil. Kom dock ihåg att allt ligger kvar i minnet: globala variabler moduler som laddats in
Rätta buggar syntaxfel logiska fel runtime-fel (inträffar under körning) behövs omfaktorering?