View Single Post
Det som er nydelig med klasser, er at det abstraherer vekk en god del av koden din, og kan innkapsle logikk for å passe på at klassevariablene er gyldige. I funksjonen du lister over, så er det egentlig ikke noen vits, ettersom du antageligvis bare kommer til å kalle calculate_X én gang. Da hadde det vært like greit å ha en modul som het ABCformula, med funksjonen calculate_X(a,b,c). Med den første løsningen blir det 2-3 kodelinjer: (import), instansiering, kall. Med den andre så blir det 1-2 linjer: (import), kall. Det ville gitt mer mening om klassen kunne løse flere typer polynomer eller noe, slik at det var litt mer dynamisk hva du ga inn, og forskjellig hva du ville ha ut.

Klasser blir litt mer nyttige når du ønsker å ha en instans av noe, som du kan gi en initialtilstand og så gjøre operasjoner basert på den tilstanden. Det mest nyttige er i situasjoner hvor du er nødt til å lagre mellomtilstander, og så gi denne tilbake igjen til neste runde av en kalkulasjon eller for en tilstandsmaskin. En ting jeg bruker klasser til, er ting som kjører i tråder og skal ha én instans per ressurs - gjerne i en egen tråd. Si at du kommuniserer med et eller annet objekt, som ikke er ditt eget program. Det kan være en mikrokontroller som du snakker UART/SPI med, en socket som snakker med en terminal-service/nettside e.l. Her er det veldig greit å ha en klasse som du kan gi start-parametere til (baudrate/comport eller adresse/port), og så har klassen funksjoner som lar deg sende og lese et visst antall bytes, samt lukke forbindelsen. Tenk så at du ønsker å snakke med ti slike enheter samtidig, fra samme kodebase.

Fordelen med å ha det som klasse-instanser, er at du ikke trenger å huske noe annet enn hva instansen heter. Med en gang du har gitt klassen den informasjonen den trenger, så er det "off your hands". Du kommuniserer nå bare via å gjøre funksjonskall på instans-objektet. Instansen selv kan huske hvem som skal kobles til, holde styr på hvorvidt forbindelsen fortsatt er oppe, og lagre unna både inngående og utgående data. Enten for å spare det til du har tid å lese det, eller for å skrive masse data til en treig enhet. Du kan enkelt spørre alle instansene (i loop) om de har noe data til deg. Det er superenkelt å lukke alle ressursene. Alternativet hadde vært en haug med funksjoner som tok masse input-parametre for å finne ut hvilken tilkobling du mener.

En annen ting er også arv, hvor du kan arve en funksjon og så gjøre noe spesielt i den nye klassen. Tidligere har jeg brukt dette for spesielle logg-objekter som må skrive ut alt i XML, slik at neste system kan tolke resultatet. Da har jeg en klasse som kan bygge meldinger på riktig format, men som bare skriver alt ut til stdout. Så lager jeg flere klasser som arver den originale, men i stedet skriver ut til en fil, eller utfører operasjoner på hele XML-strukturen før den skrives (konverterer til et annet format, kjører syntax-sjekker, komprimerer den, fjerner duplikater e.l.). I stedet for å ha en ultra-generell XMLLogger-klasse som tar femten parametre, så har jeg i stedet 5 mini-klasser på et par kodelinjer, som hver har et beskrivende navn over hva de gjør (XMLFileLogger, XMLNoDuplicateLogger). (Jeg husker ikke nøyaktige navn, men det understreker uansett poenget. Det var for et continuous integration-system som MÅTTE ha alt på et forhåndsbestemt format).

Python har også generatorer, som kan brukes som en slags mellomting mellom funksjoner og klasser. Si at du ønsker å få ut en god del Fibonacci-tall, men ikke alle på én gang pga. minnebegrensninger. Da kan du gjøre noe sånt som dette:

Kode

def Fibonacci(n):
    a,b = 1,1
    counter = 0
    while counter < n:
        yield a
        a,b = b,a+b
        counter += 1

fib = Fibonacci(10)
list([e for e in fib]) # Lager en liste med de ti første tallene
fib = Fibonacci(10)
next(fib) # Printer ut ett og ett tall, eller StopIteration Exception når det er tomt. I Python2 kan man bruke fib.next().
fordelen her er at du kan kalle Fibonacci(100000000000) uten problem. Du kan fortsatt hente ut ett og ett tall, men putter du de i en liste så går du tom for minne. En generell funksjon vil ikke klare det samme, uten å få vite hva de to foregående tallene var, eller starte helt på nytt hver gang. En klasse opererer på de samme prinsippene, bare med funksjoner i stedet for tilstandsvariabler, og et interface som gir deg tilgang til innholdet i klassen.
Sist endret av Dyret; 27. mai 2018 kl. 23:06.