Programstruktur
Hej,
Jag har en uppgift där jag ska omformulera en given kod i Python. Programmet som koden skapat handlar om att läsa in en datafil med data från olika mätningar som gjorts på enhetscirkeln, när programmet läst in detta ska den returnera medelvärdet för respektive mätning, jag har exempelvis sample1.txt som:
1, 0.1, 0.2, 73
1, 0.11, 0.1, 101
2, 0.23, 0.01, 17
2, 0.12, 0.15, 23
där den första siffran står för vilken batch mätningen tillhör, den andra och tredje siffran anger x-respektive y-koordinaten för punkten där mätningen är gjord och den fjärde siffran är mätvärdet.
Min uppgift är att skriva om nedanstående kod till fler men mindre funktioner för att göra den mer lättläst men jag vet inte hur jag bör tänka? Och hur jag bör dela upp denna stora funktion till flera små? Några tips? Bifogar koden nedan:
def main():
filename = input('Which data file? ')
data = dict() # Or data = {}
with open(filename, 'r') as h:
for line in h:
four_vals = line.split(',')
batch = four_vals[0]
if not batch in data:
data[batch] = []
data[batch] += [(float(four_vals[1]), float(four_vals[2]), float(four_vals[3]))] # Collect data from an experiment
for batch, sample in data.items():
if len(sample) > 0:
n = 0
x_sum = 0
for (x, y, val) in sample:
if x**2 + y**2 <= 1:
x_sum += val
n += 1
average = x_sum/n
print(batch, "\t", average)
else:
print(batch, "\tNo data")
Jag är medveten om att koden har några fel och bland annat fungerar den endast med den datan jag gett i sample1.txt men tanken är att denna ska felsökas efter att jag fått till en bättre struktur på koden.
Se till först och främst att du förstår vad koden gör, åtminstone på ett övergripande plan. Försök sen urskilja vilka "deluppgifter" koden löser. En deluppgift t.ex. är att läsa in värden från filen och fylla dictionaryt "data" med dessa värden. Sedan kan du flytta koden som löser en sådan deluppgift till en egen funktion.
När du skriver en funktion, försök göra den generell. En bra funktion är skriven så att den kan användas i olika sammanhang, under andra förhållanden. Man vill alltså t.ex. inte "hårdkoda" ett filnamn i funktionen som läser filen så att den alltid läser samma fil. Läs-funktionen bör inte heller fråga användaren efter ett filnamn, för då begränsar man hur funktionen kan användas. Istället bör man låta funktionen vara flexibel genom att ta filnamnet som ett argument.
Ofta pratar man om att funktioner ska "do one thing, and do it well".
Skaft skrev:Se till först och främst att du förstår vad koden gör, åtminstone på ett övergripande plan. Försök sen urskilja vilka "deluppgifter" koden löser. En deluppgift t.ex. är att läsa in värden från filen och fylla dictionaryt "data" med dessa värden. Sedan kan du flytta koden som löser en sådan deluppgift till en egen funktion.
När du skriver en funktion, försök göra den generell. En bra funktion är skriven så att den kan användas i olika sammanhang, under andra förhållanden. Man vill alltså t.ex. inte "hårdkoda" ett filnamn i funktionen som läser filen så att den alltid läser samma fil. Läs-funktionen bör inte heller fråga användaren efter ett filnamn, för då begränsar man hur funktionen kan användas. Istället bör man låta funktionen vara flexibel genom att ta filnamnet som ett argument.
Ofta pratar man om att funktioner ska "do one thing, and do it well".
Tusen tack! Då förstår jag mer hur jag ska försöka att dela upp texten och få till en bättre struktur. När du skriver att läs-funktionen inte bör fråga användaren efter ett filnamn och istället låta funktionen ta filnamnet som ett argument, menar du då att jag direkt ska sätta in "filename" i definitionen istället för att ha en input? Exempelvis om jag skulle fortsätta använda main() så skulle jag istället ha main(filename)?
Ja. Men för att förtydliga, min poäng är alltså inte att det är fel i sig att använda input(). Det bör bara inte göras inuti funktionen som ska läsa filen. En funktion som läser en fil behöver ju inte veta *varifrån* filnamnet kommer - det kan komma från input(), från en annan fil, från internet eller varsomhelst. Det som läs-funktionen *behöver* för att göra vad den ska, är bara själva filnamnet. Och då bör man alltså skicka det som ett argument, så att funktionen blir mer flexibel. Så funktionen skulle kunna ha strukturen
def get_data(filename):
...
...
return data
Man kan tänka att "det som funktionen behöver", det ska ges till funktionen som argument. Funktionen ska inte själv behöva gå och hämta nödvändig info (genom att till exempel anropa input).