Permalänk

Problem i Python med matriser!

Hejsan

Jag är nybörjare i Python och har ett problem med ett program som jag fått i kursuppgift att göra.
Programmet tar emot input från användaren och ska därefter rita upp en kalender i form av en prydlig tabell enligt nedan.

Må Ti On To Fr Lö Sö
1 2 3 4 5 6 7
8 9 osv.

Jag fattar att jag måste använda en matris på något sätt men hur fasen gör man för att rita ut printa ut värdena i tabellform?
Det handlar om att få till korrekt kod i funktionen outData2()

Vore otroligt tacksam för hjälp av forumet!

-----------------------------------------------------------------------------

# Det här är ett program som skriver ut en månadskalender # för ett godtyckligt år i intervallet 1900-3000. # Programmet ska ge meddelande vid felaktig inmatning vilket inte är fixat ännu # ------- Hämtar in nödvändiga moduler -------- from datetime import date # ------- Funktioner för textgränssnitt/inmatning -------- # Hämtar input för menyval def inData1() : alt = int(input(" Vilket alternativ väljer du? ")) return alt # Hämtar input för år vid menyval 2 def inData2() : inYear = int(input(" Ange årtal mellan 1900 och 3000 som du vill titta på: ")) return inYear # Hämtar input för månad vid menyval 2 def inData3() : inMonth = int(input(" Ange numret på den månad du vill titta på: ")) return inMonth # Hämtar in uppgift om dagens datum från modulen 'date' i 'datetime' vid menyval 1 def inDataTodaysDate() : d = str(date.today()) # Läs in hela datumet som anges i formatet YYYY-MM-DD av modulen inYear = int(d[0:4]) # bryt ut YYYY inMonth = int(d[5:7]) # bryt ut MM return inYear, inMonth # ------- Utskriftsdel -------- # Skriver ut rubrik för kalender på grundval av vald månad och år def outData1() : print ("\n") print (INDENT, monthList[inMonth-1][1], inYear) # Plockar ut namnet på månaden ur lista och anger inmatningsåret print (INDENT, ("Må Ti On To Fr Lö Sö")) # Förbereder utskrift kalendern def prepOutData2() : global counter if counter < monthList[inMonth-1][0] : # En loop som räknar upp månadens dagar counter += 1 outData2() else : return # Ritar ut kalendern def outData2() : # Klurar på hur kolumnerna ska bli jämna och fina, denna del ska utvecklas med en matris på något sätt global counter counterAdjust = repr(counter) print (counterAdjust.rjust(weekdayList[w_day][2]), end="") # Justerar så att den 1 i månaden hamnar under rätt veckodag prepOutData2() def testdata() : # Testvärden för kontroll, ska tas bort senare!! print ("\n") print (INDENT, "TESTVÄRDEN") print (INDENT, "valAlt:", valAlt) print (INDENT, "inYear:", inYear) print (INDENT, "inMonth:", inMonth) if leapDay == 1 : print (INDENT, "Skottår!") else: print (INDENT, "Inget skottår!") print (INDENT, totalDays, "dagar sedan den 1 jan 1900.") print (INDENT, (weekdayList[w_day][1]), "är veckodagen som månadens första dag infaller på.") print (INDENT, "Det finns", (monthList[inMonth-1][0]), "dagar i månaden.") print ("\n") # ------- Funktioner för beräkning av veckodag -------- # Funktion som fastställer om skottdag (leapDay) existerar frö valt år def calcLeapYear() : leapDay = 0 if inYear%4 == 0 and inYear%100 != 0 or inYear%400 == 0 : # Beräkningen av skottdag enligt formel i uppgiftslydelsen leapDay += 1 return leapDay else : return leapDay # Funktionen som räknar ut veckodag för den 1 i månaden def calcDay() : inDate = date(inYear, inMonth, 1) # Anger YYYY och MM i modulen som använder systemet YYYY-MM-DD delta = inDate - STARTDATE # Totalt antal dagar sedan 1 jan 1900 totalDays = int(delta.days) w_day =(totalDays%7) # Räknar ut resten av divisionen so return totalDays, w_day # -------- Huvudprogram -------- INDENT = str(" ") # Tomma tecken i början av indragna rader STARTDATE = date(1900, 1, 1) # ZERODATE - En konstant, måndagen den 1 jan 1900, utifrån vilken alla uträkningar ska göras counter = 0 # global variabel för att lösa utskriften i outData2() och förberedelsen till den samma i prepOutData2() print (INDENT*8, "Kalenderprogram") print ("\n") print (INDENT, ("(1) Se denna månads kalender")) print (INDENT, ("(2) Ange år och månad")) valAlt = inData1() if valAlt == 1 : # Automatisk inläsning av datum inYear, inMonth = inDataTodaysDate() else : # Om "alt" inte är lika med "1", utan istället "2" ska programmet läsa in nytt datum inYear = inData2() inMonth = inData3() leapDay = calcLeapYear() # Lista över månaderna med 2 positioner: antal dagar och namn monthList = [[31, "januari"], [28+leapDay, "februari"], [31, "mars"], [30, "april"], [31, "maj"], [30, "juni"], [31, "juli"], [31, "augusti"], [30, "september"], [31, "oktober"], [30, "november"], [31, "december"]] totalDays, w_day = calcDay() # Lista över veckodagarna med 3 positioner: löpnummer, veckodag, samt justeringsvärde för att den 1 i månaden ska hamna rätt weekdayList = [[0, "Må", 6], [1, "Ti", 9], [2, "On", 12], [3, "To", 15], [4, "Fr", 18], [5, "Lö", 21], [6, "Sö", 24]] outData1() prepOutData2() testdata()

Permalänk

Snälla, lägg koden i code-tagg

Visa signatur

Anything that can go wrong will go wrong.

Permalänk
Medlem

Vad god använd code-taggar inom koden du vill visa.
Sen istället för att pasta hela din kod, peka istället ut och pasta den del du vill ha hjälp med.

Visa signatur

Corsair 16GB (4x4096MB) CL9 1600Mhz | Asus P8Z77-V PRO |
Samsung SSD Basic 830-Series 256GB | Intel Core i7 3770K 3,5Ghz |
Asus Xonar Essence STX | Noctua NH-U9B SE2 | Antec Performance One P280 | Corsair HX 850W 80+ Gold Modulär | MSI GTX 770

Permalänk

Sorry, får erkänna att jag inte vet vad det är. Vad menas med det?

Permalänk
Inaktiv
Skrivet av CarlKabul:

Sorry, får erkänna att jag inte vet vad det är. Vad menas med det?

Det innebär att du trycker på symbolen med ett "#" på när du skapar ditt inlägg

if (codeTaggar) inlägg.isLäsbart(); else inlägg.fult();

Permalänk

Allright, fattar varför. Indragningarna försvinner annars. Men hur gör jag?

Tack för hjälpen. Redigerade om inlägget, hoppas det ska stämma nu!

Permalänk

Det faktum att du har justeringsvärden i weekDayList kan vara en ledtråd till att uppgiftsförfattaren inte har tänkt sig en lösning med matriser utan att det räcker med att justera raderna vid utskrift. Innan du skriver ut första dagen får du indentera den raden ett antal steg. Byt rad när w_day är mindre än den föregående utskrivna dagen.

Permalänk

Det är jag som har gissat att det jag behöver justeringsvärden. Som jag förstått det men ej helt säker - vill de att man ska använda en matris.
Jag har indenterat så att det första datumet (alltså 1:e )hamnar under rätt veckodag.

Tack för tipset, tror jag förstår - men hur gör man?

Permalänk

Ok, vill du ha matriser så fixar vi det, men det är ju inte meningen att jag skall skriva koden åt dig. Lite för du allt göra själv...

Om offset är vilken veckodag (0-6) i veckan tabellen skall starta på. Vad kommer

tabell[(datum + offset) / 7][(datum + offset) % 7] = datum

att göra?

Permalänk

Okej.
Om jag förstår rätt så:
Värdena för tabell för det första datumet i en månad som startar med en måndag blir:
tabell[0][1]

För det andra datumet, en tisdag blir det:
tabell[0][3]

Men hur ska jag göra föra att skriva ut en tabell av det?

Permalänk

Jag är hopplöst fast. Förstår inte hur jag ska lösa det här.
Vad gör jag för fel? Får felmeddelande. Har omarbetat med hjälp av tips ovan.

# ------- Hämtar in nödvändiga moduler -------- from datetime import date # ------- Funktioner för textgränssnitt/inmatning -------- # Hämtar input för menyval def inData1() : alt = int(input(" Vilket alternativ väljer du? ")) return alt # Hämtar input för år vid menyval 2 def inData2() : inYear = int(input(" Ange årtal mellan 1900 och 3000 som du vill titta på: ")) return inYear # Hämtar input för månad vid menyval 2 def inData3() : inMonth = int(input(" Ange numret på den månad du vill titta på: ")) return inMonth # Hämtar in uppgift om dagens datum från modulen 'date' i 'datetime' vid menyval 1 def inDataTodaysDate() : d = str(date.today()) # Läs in hela datumet som anges i formatet YYYY-MM-DD av modulen inYear = int(d[0:4]) # bryt ut YYYY inMonth = int(d[5:7]) # bryt ut MM return inYear, inMonth # ------- Utskriftsdel -------- # Skriver ut rubrik för kalender på grundval av vald månad och år def outData1() : print ("\n") print (INDENT, monthList[inMonth-1][1], inYear) # Plockar ut namnet på månaden ur lista och anger inmatningsåret print (INDENT, ("Må Ti On To Fr Lö Sö")) def testdata() : # Testvärden för kontroll, ska tas bort senare!! print ("\n") print (INDENT, "TESTVÄRDEN") print (INDENT, "valAlt:", valAlt) print (INDENT, "inYear:", inYear) print (INDENT, "inMonth:", inMonth) if leapDay == 1 : print (INDENT, "Skottår!") else: print (INDENT, "Inget skottår!") print (INDENT, totalDays, "dagar sedan den 1 jan 1900.") print (INDENT, (weekdayList[w_day][1]), "är veckodagen som månadens första dag infaller på.") print (INDENT, "Det finns", (monthList[inMonth-1][0]), "dagar i månaden.") print ("\n") # ------- Funktioner för beräkning av veckodag -------- # Funktion som fastställer om skottdag (leapDay) existerar frö valt år def calcLeapYear() : leapDay = 0 if inYear%4 == 0 and inYear%100 != 0 or inYear%400 == 0 : # Beräkningen av skottdag enligt formel i uppgiftslydelsen leapDay += 1 return leapDay else : return leapDay # Funktionen som räknar ut veckodag för den 1 i månaden def calcDay() : inDate = date(inYear, inMonth, 1) # Anger YYYY och MM i modulen som använder systemet YYYY-MM-DD delta = inDate - STARTDATE # Totalt antal dagar sedan 1 jan 1900 totalDays = int(delta.days) w_day = (totalDays%7) # Räknar ut resten av divisionen so return totalDays, w_day # Ritar ut kalendern def outData2() : # Klurar på hur kolumnerna ska bli jämna och fina, denna del ska utvecklas med en matris på något sätt counter = int(1) tabell = 2*[None] tabell[(counter + w_day) / 7][(counter + w_day) % 7] = counter while counter < monthList[inMonth-1][0] : print (tabell) counter += 1 else : return # -------- Huvudprogram -------- INDENT = str(" ") # Tomma tecken i början av indragna rader STARTDATE = date(1900, 1, 1) # ZERODATE - En konstant, måndagen den 1 jan 1900, utifrån vilken alla uträkningar ska göras print (INDENT*8, "Kalenderprogram") print ("\n") print (INDENT, ("(1) Se denna månads kalender")) print (INDENT, ("(2) Ange år och månad")) valAlt = inData1() if valAlt == 1 : # Automatisk inläsning av datum inYear, inMonth = inDataTodaysDate() else : # Om "alt" inte är lika med "1", utan istället "2" ska programmet läsa in nytt datum inYear = inData2() inMonth = inData3() leapDay = calcLeapYear() # Lista över månaderna med 2 positioner: antal dagar och namn monthList = [[31, "januari"], [28+leapDay, "februari"], [31, "mars"], [30, "april"], [31, "maj"], [30, "juni"], [31, "juli"], [31, "augusti"], [30, "september"], [31, "oktober"], [30, "november"], [31, "december"]] totalDays, w_day = calcDay() # Lista över veckodagarna med 3 positioner: löpnummer, veckodag, samt justeringsvärde för att den 1 i månaden ska hamna rätt weekdayList = [[0, "Må", 6], [1, "Ti", 9], [2, "On", 12], [3, "To", 15], [4, "Fr", 18], [5, "Lö", 21], [6, "Sö", 24]] outData1() outData2() testdata()

Lagat
Permalänk
Medlem

Snälla, använd code-taggarna eller extern paste-tjänst om du vill att koden skall vara läsbar.

Permalänk
Hedersmedlem

Får du felmeddelande är det ganska svårt för oss att gissa vad det meddelandet var. Skriv med det!

Permalänk

All right. Felmeddelandet lyder:
Traceback (most recent call last):
File "C:\Python33\test.py", line 106, in <module>
outData2()
File "C:\Python33\test.py", line 77, in outData2
tabell[(counter + w_day) / 7][(counter + w_day) % 7] = counter
TypeError: list indices must be integers, not float

Jag började programmera bara för ett par veckor sedan. Det har gått bra och varit väldigt skojigt fram tills nu när jag sitter hårt fast...

Permalänk
Medlem

Felmeddelandet säger en hel del användbart.
Fundera på vilka värden

(counter + w_day) / 7

kan anta.

Permalänk
Skrivet av CarlKabul:

Men hur ska jag göra föra att skriva ut en tabell av det?

Det vanliga är att man använder en loop. Python har en del smidiga varianter. Jag ser i din kod att du inte har använt någon av dem så läs på om range och for-loopen.

Permalänk
Hedersmedlem
Skrivet av CarlKabul:

# Hämtar input för menyval def inData1() : alt = int(input(" Vilket alternativ väljer du? ")) return alt # Hämtar input för år vid menyval 2 def inData2() : inYear = int(input(" Ange årtal mellan 1900 och 3000 som du vill titta på: ")) return inYear # Hämtar input för månad vid menyval 2 def inData3() : inMonth = int(input(" Ange numret på den månad du vill titta på: ")) return inMonth

Just nu utförs ingen felkontroll på input, och det är logik som upprepas (och mer kommer tillkomma med felkontroll). En omfaktorering skulle kunna vara t ex:

def get_int(msg, allowed_range, range_err_msg): while True: try: resp = int(input(' {}: '.format(msg))) except ValueError: print('Fel: du måste ange ett heltal. Försök igen.') continue if resp in allowed_range: return resp else: print('Fel: {}. Försök igen'.format(range_err_msg)) # Använd beskrivande namn istf "Data1", "Data2", osv. Man vet aldrig när man # refaktorerar, och då vill man inte behöva ändra en godtycklig numrering. def get_alternative(): return get_int('Välj alternativ', [1, 2], 'ej giltigt alternativ') def get_year(): return get_int('Ange årtal mellan 1900 och 3000 som du vill titta på', range(1900, 3001), 'årtal ej inom godkänt intervall') def get_month(): return get_int('Ange numret på den månad du vill titta på', range(1, 13), 'månadsnummer måste vara inom 1 och 12')

När man bryter ut saker i funktioner så ska man tänka på koden i termen av logiska enheter, och undvika att upprepa sig själv. Här har du en uppgift som ska upprepas tre gånger och ska innehålla samma typ av felkontroller. Det som skiljer är meddelanden och tillåtna invärden, så faktorera ut dessa.

Skrivet av CarlKabul:

def inDataTodaysDate() : d = str(date.today()) # Läs in hela datumet som anges i formatet YYYY-MM-DD av modulen inYear = int(d[0:4]) # bryt ut YYYY inMonth = int(d[5:7]) # bryt ut MM return inYear, inMonth

Enklare är att låta datumet vara ett objekt, istf att omvandla det till/från strängar/heltal. Ovanstående kan exempelvis skrivas:

def today_year_month(): d = date.today() return d.year, d.month

Ett ytterligare, egentligen mer naturligt, alternativ är att helt enkelt returnera ett `datetime.date()`-objekt och behandla detta vidare i efterföljande kod.

Skrivet av CarlKabul:

def calcLeapYear() : leapDay = 0 if inYear%4 == 0 and inYear%100 != 0 or inYear%400 == 0 : # Beräkningen av skottdag enligt formel i uppgiftslydelsen leapDay += 1 return leapDay else : return leapDay

Låt din funktion ta `inYear` som inparameter istf att förlita sig på globala variabler. Det är mer logiskt sammanhängande; dvs: `def calcLeapYear(inYear):`.

Först kan man åtminstone notera att det finns färdiga funktioner i Python för att bestämma skottår (exempelvis `calendar.isleap()` (notera att modulen `calendar` innehåller en del logik som nog kan vara användbar i det här fallet), eller använda `datetime.date()` för att se vilket löpande årsdygnsnummer t ex 1 mars har), men det är inget fel på logiken inom det valda årsintervallet (om inget oväntat händer innan år 3000).

I vilket fall så är det naturligare att utnyttja att booleanska värden (`True`/`False`) automatiskt tolkas som `1`/`0` i Python (kolla vad t ex `True+True` ger dig för svar). Din skottårsfunktion kan alltså ekvivalent uttryckas som:

def is_leap_year(year): return year % 4 == 0 and year % 100 != 0 or year % 400 == 0

Detta returnerar `True`, dvs `1`, om vi har ett skottår och `False`, dvs `0`, om vi inte har det.

Skrivet av CarlKabul:

# Funktionen som räknar ut veckodag för den 1 i månaden def calcDay() : inDate = date(inYear, inMonth, 1) # Anger YYYY och MM i modulen som använder systemet YYYY-MM-DD delta = inDate - STARTDATE # Totalt antal dagar sedan 1 jan 1900 totalDays = int(delta.days) w_day = (totalDays%7) # Räknar ut resten av divisionen so return totalDays, w_day

Ett `datetime.date()`-objekt har metoden `weekday()`, så ovanstående kan t ex skrivas:

def first_weekday_of_month(year, month): return date(year, month, 1).weekday()

Nu returnerade jag inte totala antalet dagar sedan 1900-01-01, men jag ser inte var det behövs, och logiskt kan det i så fall ligga i en annan funktion. Vi ser också att om vi jobbat med `datetime.date()`-objekt hela tiden så hade dessa saker inte ens behövt nyskrivna funktioner, då dessa objekt redan innehåller all denna logik, vilket är just kraften med objekt.

Skrivet av CarlKabul:

# Ritar ut kalendern

Bara för att demonstrera ett koncept med strängformatering:

>>> for i in range(2, 6): ... i = (i-1)*3 ... print('| {:>3} {:>3} {:>3} |'.format(i, i+1, i+2)) ... | 3 4 5 | | 6 7 8 | | 9 10 11 | | 12 13 14 |

Notera hur de tvåsiffriga talen tar upp lika mycket plats ({:>3} betyder "skriv strängen högerjusterad i ett block med tre tecken") som de ensiffriga i utskriften. Det kan nog vara till hjälp vid justerad kalenderutskrift.

Skrivet av CarlKabul:

counter = int(1) ... INDENT = str(" ") # Tomma tecken i början av indragna rader

Du behöver inte använda explicit typkonvertering här i Python. Ovanstående är ekvivalent med:

counter = 1 ... INDENT = " "

Citationstecken anger automatiskt att det är en sträng, och inga citationstecken anger att `1` är ett heltal. `1.` hade varit ett flyttal, `[1, 2]` hade varit en lista, `(1, 2)` hade varit en tuple, osv.

Skrivet av CarlKabul:

# -------- Huvudprogram --------

Ett vanligt [1, 2] idiom i Python är att lägga all "huvudkod" i en funktion som man döper till `main()`, och sist i programmet skriva:

if __name__ == '__main__': # Om programmet körs på egen hand är detta sant. main() # Detta kör huvudprogramkoden som ligger i en separat funktion

Först ser det bara onödigt ut, men det har en del trevliga egenskaper: det håller programmet rent från onödiga globala variabler, det möjliggör import av ett program som en modul på ett vettigt sätt, det möjliggör enhetstester, etc.

Skrivet av CarlKabul:

# Lista över månaderna med 2 positioner: antal dagar och namn monthList = [[31, "januari"], [28+leapDay, "februari"], [31, "mars"], [30, "april"], [31, "maj"], [30, "juni"], [31, "juli"], [31, "augusti"], [30, "september"], [31, "oktober"], [30, "november"], [31, "december"]] ... # Lista över veckodagarna med 3 positioner: löpnummer, veckodag, samt justeringsvärde för att den 1 i månaden ska hamna rätt weekdayList = [[0, "Må", 6], [1, "Ti", 9], [2, "On", 12], [3, "To", 15], [4, "Fr", 18], [5, "Lö", 21], [6, "Sö", 24]]

Python har redan inbyggda strängar för språkspecifika veckodags- och månadsnamn. Exempel:

>>> from datetime import date >>> import locale >>> locale.setlocale(locale.LC_TIME, 'sv_SE') >>> date.today().strftime("%c") 'ons 30 okt 2013 00:00:00'

`datetime.date()` vet hur många dagar det är i varje månad. Justeringsvärdet förstår jag inte anledningen till just nu.

Visa signatur

Nu med kortare användarnamn, men fortfarande bedövande långa inlägg.

Permalänk

Stort tack!
Skriver från en marockansk landsväg och kommer vara på fortsatt resande fot under en vecka. Ska gå igenom allting noga när lediga stunder uppstår. Återkommer. Och än en gång: Tack till er (speciellt phz) som orkat coacha. Känns som jag kan släppa mycket av ångesten nu och det ska vara möjligt att gå vidare. Skönt!

Permalänk

Har kollat på ett par saker:
Tror jag har koll på hur felhanteraren arbetar. Det är en väldigt elegant lösning som ligger bortom den nivå jag befinner mig på. Hade aldrig lyckats klura ut det själv... tack.
Inser nyttan med att döpa funktionerna med namn som beskriver dem och varför man ska hålla sig undan siffror. Att döpa input-funktioner till "get" verkar logiskt.
Har sett main-funktion på annat håll tidigare och nu infört en sådan för huvudprogramkoden. Men varför skriver man "if __name__ == '__main__':" ? Förstår nyttan tror jag av att ha huvudkoden i en funktion, men måste medge att nödvändigheten av if-satsen går mig förbi...
Är koden nedan i min main-funktion acceptabel, och hur jag kallar på get-funktionerna, eller ser ska jag ska göra på annat sätt?

Jag är medveten om att det finns färdiga moduler (datetime, calender) i Python som vore enklare att använda för uppgiften, men eftersom det är en grundläggande kurs ska vi räkna ut skottår mm. med egna funktioner.

När det gäller de andra synpunkterna ska jag testa mig fram vidare. Inser att jag har en hel del att öva på i syfte att formulera kod som är mer precis i sin natur och vackrare till sin utformning. Tack för visat tålamod med en nybörjare!

def menu(): print (INDENT*8, "Kalenderprogram") print ("\n") print (INDENT, ("(1) Se denna månads kalender")) print (INDENT, ("(2) Ange år och månad")) def get_int(msg, allowed_range, range_err_msg): while True: try: resp = int(input(' {}: '.format(msg))) except ValueError: print(' Fel: Du måste ange ett heltal. Försök igen!') continue if resp in allowed_range: return resp else: print(' Fel: {}. Försök igen!'.format(range_err_msg)) def get_alternative(): return get_int('Välj alternativ', [1, 2], 'Ej giltigt alternativ') def get_year(): return get_int('Ange årtal mellan 1900 och 3000 som du vill titta på', range(1900, 3001), 'Årtal ej inom godkänt intervall') def get_month(): return get_int('Ange numret på den månad du vill titta på', range(1, 13), 'Månadsnummer måste vara inom 1 och 12') def main(): # Huvudprogrammet menu() if get_alternative() == 1 : print (INDENT, "TESTVÄRDE: Alternativ 1 valt") else : in_Year = get_year() in_Month = get_month() print (INDENT, "TESTVÄRDE: Alternativ 2 valt") print (INDENT, in_Year) print (INDENT, in_Month) #--------------------------------------------------------------------------------------------- INDENT = str(" ") __name__ = "__main__" if __name__ == '__main__': main() # Detta kör huvudprogramkoden som ligger i en egen funktion

Permalänk
Hedersmedlem
Skrivet av CarlKabul:

Har sett main-funktion på annat håll tidigare och nu infört en sådan för huvudprogramkoden. Men varför skriver man "if __name__ == '__main__':" ? Förstår nyttan tror jag av att ha huvudkoden i en funktion, men måste medge att nödvändigheten av if-satsen går mig förbi...
Är koden nedan i min main-funktion acceptabel, och hur jag kallar på get-funktionerna, eller ser ska jag ska göra på annat sätt?

[…]

__name__ = "__main__" if __name__ == '__main__': main() # Detta kör huvudprogramkoden som ligger i en egen funktion

Den fetstilade biten ska inte vara med. `__name__` är en speciell variabel som sätts automatiskt av Python själv när du kör programmet. Om du kör programmet på egen hand, så sätts denna variabel till strängen `"__main__"`, vilket är det vi testar efter: den if-satsen utförs alltså bara om programmet körs explicit.

Ifall du hade importerat filen som en modul ifrån ett annat program (säg att du t ex ville återanvända `get_int()`-funktionen i ett annat program, utan att copy+pasta) så hade `__name__` i stället haft ett annat värde när den importerade filen evaluerats (specifikt namnet på programmet ifrån vilket importen skett).

Så om du helt enkelt bara tar bort den fetstilade biten så bör ditt program fungera precis som nu, fast på ett mer användbart sätt. Detta är som sagt främst en vanlig konvention, och det fungerar ju att göra på andra sätt också, men då det i regel är så här program är uppbyggda så kan det vara bra att vara bekant med detta.

Skrivet av CarlKabul:

Har kollat på ett par saker:
Tror jag har koll på hur felhanteraren arbetar. Det är en väldigt elegant lösning som ligger bortom den nivå jag befinner mig på. Hade aldrig lyckats klura ut det själv... tack.

Det exempel som officiella dokumentationen använder för att demonstrera `try`/`except`-konstruktionen är just `int(input(…))`, så där står en lite utförligare förklaring över vad som händer. Det är ett ytterst vanligt mönster i Python att "huvudlöst" (fast egentligen inte) försöka utföra operationer som om variablerna vore av rätt typ, t ex ovan att användaren matar in just något som kan tolkas som ett giltigt argument till `int()`. Ifall antagandet stämmer: bra, då går man bara vidare. Ifall antagandet inte stämmer så kommer i detta fall `int()` klaga högljutt och "höja ett undantag" ("raise an exception"); i detta fall `ValueError`. Obehandlat så får detta programmet att "krascha", liksom ditt program gjorde tidigare med:

Skrivet av CarlKabul:

Traceback (most recent call last): File "C:\Python33\test.py", line 106, in <module> outData2() File "C:\Python33\test.py", line 77, in outData2 tabell[(counter + w_day) / 7][(counter + w_day) % 7] = counter TypeError: list indices must be integers, not float

Här har programmet höjt `TypeError`, och därför stannat exekveringen. Men: man kan fånga dessa fel genom `try`/`except`-konstruktionen. I `get_int()` ovan så testar (`try`) vi att omvandla användarens input till ett heltal, och om detta genererar undantaget `ValueError` (`except ValueError:`) så betyder det att vi inte fick ett heltal. I stället för att krascha körs då det som är i `except`-blocket. I detta fall så skriver vi ut vad som är fel, och sedan betyder `continue`, för då kommer `while`-loopen som vi är inuti börja om, och programmet frågar åter efter input på samma sätt som tidigare. När vi väl fått något som duger så går vi vidare till vårt nästa test.

Vad gäller `if resp in allowed_range:` så betyder det: "om `resp` har ett värde som även finns i objektet `allowed_range`:" — `in` är en kraftfull konstruktion i Python, och det kan jobba med alla objekt som är "itererbara". Om detta inte är sant så meddelar vi detta till användaren och börjar om loopen.

Men om alltså först användarens input är ett heltal, och det även är med bland tillåtna värden, så returnerar vi detta, och när `return`-uttrycket används så avbryts automatiskt funktionen.

Skrivet av CarlKabul:

Är koden nedan i min main-funktion acceptabel, och hur jag kallar på get-funktionerna, eller ser ska jag ska göra på annat sätt?
[…]

if get_alternative() == 1 : print (INDENT, "TESTVÄRDE: Alternativ 1 valt") else :

Denna kodbit reagerar jag på. Den fungerar just nu när det bara är två alternativ att välja på, och `get_alternative()` internt ser till att bara tillåta värdena `1` och `2` (i din allra första version så skulle inmatning t ex `7` likväl behandlas som `2`), men skulle programmet utökas så skulle detta behöva skrivas om, och det ser logiskt lite "slappt" ut . Snarare, i mina ögon:

alternative = get_alternative() if alternative == 1: print (INDENT, "TESTVÄRDE: Alternativ 1 valt") elif alternative == 2: […] else: print('Här blev det ett logikfel i programmet! alternative = {}'.format(alternative))

Detta blir mer läsbart, på grunden att man direkt av att bara titta på denna kodbit att "jaha, det är två alternativ som heter '1' och '2'", utan att behöva hoppa upp till menyfunktionen.

Den sista `else`-satsen ska egentligen aldrig kunna nås ifall `get_alternative()` fungerar som den ska, och kan plockas bort när testningsstadiet lämnas. En mer generell lösning vore att definiera alternativen i en lista, utifrån vilken menyn och tillåtna värden automatiskt genereras, men det är överdrivet att lägga tid på här .

Skrivet av CarlKabul:

INDENT = str(" ")

Globala variabler är vanligen en "styggelse". I detta fall så vore en "korrektare" lösning kanske att t ex bygga en egen `print`-funktion och inkludera indenteringen där, t ex:

def print_i(msg, n=1): indent = " " print('{}{}'.format(indent*n, msg))

`print_i('hej')` skriver ut "hej" med ett indrag (standardvärdet för n, dvs om bara ett argument ges, är 1), dvs "  hej". `print_i('hopp', 4)` skriver ut "        hopp". Än mer naturligt vore kanske att göra en utskriftsklass, men det skulle innehålla väldigt många koncept som ni inte behandlat än.

Genom att bryta ut detta i en funktion så slipper du skriva `print(INDENT, […])` hela tiden, och om du skulle vilja ändra utskriften på något sätt utöver att bara ändra indenteringens längd så kan du göra det centraliserat. Det är logik som upprepas många gånger i koden, och då passar det bättre att separera ut denna.

Skrivet av CarlKabul:

Jag är medveten om att det finns färdiga moduler (datetime, calender) i Python som vore enklare att använda för uppgiften, men eftersom det är en grundläggande kurs ska vi räkna ut skottår mm. med egna funktioner.

Det låter rimligt. Att använda t ex `d.year` istf att omvandla `d` till en sträng och parsea ut året bör dock vara att föredra i vilket fall. `import calendar` kanske räknas som "för mycket" hjälp, dock, även om det kräver en hel del förståelse för att använda moduler på ett bra sätt också.

Skrivet av CarlKabul:

När det gäller de andra synpunkterna ska jag testa mig fram vidare. Inser att jag har en hel del att öva på i syfte att formulera kod som är mer precis i sin natur och vackrare till sin utformning.

Det finns ett par olika delar i att skriva "bra" kod: "bra" betyder allt som oftast "läsbar", snarare än "kompakt" eller "hypereffektiv" på egna ben. Men "läsbar" för vem? Den bör vara läsbar av någon som är van vid språket, vilket innebär att den bör använda vedertagna konstruktioner. Då får man vanligen automatiskt prestanda och kompakthet på köpet (de lösningar som är vedertagna är det av en anledning). Tricket är att lära sig dessa konstruktioner, och det kommer med övning och att ständigt läsa och utvecklas. Många insikter kommer inte förrän man gjort på "fel" sätt och verkligen gått in i väggen för att man märkt att det inte är hållbart i längden.

Det gäller också att lära sig strukturera upp programmet i logiska bitar, och separera ut saker som naturligt hör ihop i funktioner. Gör man detta rätt från början så kan det gå ruskigt snabbt att bygga upp robusta program. Python har egenskapen att ens `main()`-funktion ofta kan (och bör) se ut som ren pseudokod som bara stolpar upp logiken för programmets kodväg, medans alla tunga lyft sköts av funktioner/klasser.

Men ja, allt sådant kommer av övning, och man blir för den delen aldrig fullärd.

Visa signatur

Nu med kortare användarnamn, men fortfarande bedövande långa inlägg.

Permalänk

Toppen, saker klarnar allt mer. Har funderat och arbetat ett par varv till med dina nya kommentarer i åtanke. Hade väldigt stor hjälp av exemplen och förklaringarna i ditt förra inlägg. Insikten i hur man använder "{" och ".format" gjorde mycket. Samt tipsen om hur tabeller med högerjusterade, ":>3", block fungerar.

Har nu en , hoppas jag, slutgiltig version av programmet där en tabell över kalendern ritas upp med prydliga rader. Det tog mycket längre tid i anspråk än jag räknat med. Återigen: TACK!

# Det här är ett program som skriver ut en månadskalender # för ett godtyckligt år i intervallet 1900-3000. # Programmet ger felmeddelande vid felaktig inmatning. # ------- Hämtar in nödvändiga moduler -------- from datetime import date # ------- Funktioner för indentering/textgränssnitt/felhantering -------- def print_i(msg, n=1): # Egen print-funktion med indentering för att slippa global indent-variabel indent = " " print('{}{}'.format(indent*n, msg)) # Indentering med fyra blanksteg, ev multiplikator följt av meddelandet def menu(): # Skriver ut menyn print_i ("Kalenderprogram", 2) print ("\n", end="") print_i ("(1) Se denna månads kalender", 1) print_i ("(2) Ange år och månad", 1) def get_int(msg, allowed_range, range_err_msg): # Felhanterare som kontrollerar resp. get-funktion genom att "fånga upp"... while True: try: resp = int(input(" {}: ".format(msg))) # Klamrarna lämnar utrymme för meddelandet (msg) except ValueError: # ...om svaret (resp) EJ är integer... print_i(("Fel: Du måste ange ett heltal. Försök igen!"), 1) continue if resp in allowed_range: return resp # Skickar tillbaka ett tillåtet svar else: # ....eller är integer MEN EJ matchar tillåtet intervall... = NY PRÖVNING print_i (("Fel: {}. Försök igen!".format(range_err_msg)), 1) # Klamrarna lämnar utrymme för meddelande om fel intervall (range_err_msg) # ------- Funktioner för felhantering/omstart av programmet ------- def get_alternative(): # Skickar info om meddelande för val, tillåtet intervall samt intervallets felmeddelande till felhanteraren return get_int("Välj alternativ", [1, 2], "Ej giltigt alternativ") def get_year(): # Skickar info om meddelande får årtal, tillåtet intervall samt intervallets felmeddelande till felhanteraren return get_int("Ange årtal mellan 1900 och 3000 som du vill titta på", range(1900, 3001), "Årtal ej inom godkänt intervall") def get_month(): # Skickar info om meddelande för månadsval, tillåtet intervall samt intervallets felmeddelande till felhanteraren return get_int("Ange numret på den månad du vill titta på", range(1, 13), "Månadsnummer måste vara inom 1 och 12") def get_run_again(): # Skickar info val för omstart resp. avslutning, tillåtet intervall samt intervallets felmeddelande till felhanteraren return get_int("(1) Kör programmet igen\n (2) Avsluta \n Ange val", [1, 2], "Ej giltigt alternativ") # -------- Hämtar automatisk uppgift om dagens datum --------- def today_year_month(): d = date.today() # Anropar "date" i "datetime" vid menyval 1 inYear = d.year inMonth = d.month return inYear, inMonth # ------- Ritar ut kalendern -------- def print_calender(wDay, leapDay, inYear, inMonth): # Lista över veckodagarna med 3 positioner: löpnummer, veckodag, samt justeringsvärde för att den månadens första dag ska hamna rätt weekdayList = [[0, "Må", 6], [1, "Ti", 10], [2, "On", 14], [3, "To", 18], [4, "Fr", 22], [5, "Lö", 26], [6, "Sö", 30]] # Lista över månaderna med 2 positioner: antal dagar och namn monthList = [[31, "januari"], [28+leapDay, "februari"], [31, "mars"], [30, "april"], [31, "maj"], [30, "juni"], [31, "juli"], [31, "augusti"], [30, "september"], [31, "oktober"], [30, "november"], [31, "december"]] print ("\n", end="") print_i (inYear, 1) # Skriv ut årtal print_i (monthList[inMonth-1][1], 1) # Skriver ut namnet på månaden print_i ("Må Ti On To Fr Lö Sö", 1) c = 0 while c < monthList[inMonth-1][0] : # Loop som räknar upp månadens dagar... c += 1 # ...med variabeln c if c == 1: # För mådandens första datum... print ("1".rjust(weekdayList[wDay][2]), end=" ") # ...justera med värdet i tredje pos. i weekdayList så att utskriften börjar under rätt veckodag if wDay == 7 : # Eftersom sön = "6" (mån = "0"), ska radbrytning ske vid "7" print ("\n", " ", end="") wDay = 0 # "7" är ingen giltig dag, därför ge värdet för måndag if c > 1: print ("{:>3} ".format(c), end="") # Skriv ut datumsiffra högercentrerat i block om tre wDay += 1 # Räkna upp veckodagen innan nästa varv alt. retur else : print ("\n") return # ------- Beräkning av veckodag/skottdag -------- def first_weekday_of_month(inYear, inMonth): # Funktion som räknar ut veckodag för dag 1 i månaden return date(inYear, inMonth, 1).weekday() def is_leap_year(year): # Funktion som fastställer om skottdag (leapDay) existerar för valt år return year % 4 == 0 and year % 100 != 0 or year % 400 == 0 # Boolsk funktion, returnerar 1 för skottår, annars 0 # -------- Main-kod -------- def main(): menu() alternative = get_alternative() if alternative == 1: # Vid menyval "1"... inYear, inMonth = today_year_month() # ... läs in dagens datum elif alternative == 2: # Om menyval "2" läsa in nytt datum geanom att... inYear = get_year() # ...hämta in värde för årtal... inMonth = get_month() # ...respektive månad. else: print("Här blev det ett logikfel i programmet! alternative = {}".format(alternative)) # Meddelar vid felkodning leapDay = is_leap_year(inYear) # Hämtar in värde för ev skottdag wDay = first_weekday_of_month(inYear, inMonth) # Hämtar in värde för veckodag print_calender(wDay, leapDay, inYear, inMonth) run_again = get_run_again() if run_again == 1: print ("\n") main() elif run_again == 2: return else: print("Här blev det ett logikfel i programmet! run_again = {}".format(alternative)) # Meddelar vid felkodning # -------- Pseudokod -------- if __name__ == '__main__': # main()

Permalänk
Hedersmedlem

Jag tycker det ser rätt bra ut. Jag anstränger mig lite extra nu för att hitta små anmärkningar. Det är egentligen främst "stilmässiga" sådana, och vissa onödigt krångliga konstruktioner som kommer från ovana — programmet ser robust ut! Du kan se detta som "överkursläsning" till en regnig dag om du vill (förutom min allra sista mening i hela detta inlägg, som jag tycker du bör läsa). Ska du programmera fler uppgifter i Python så kan det dock vara bra, då det visar några nya användbara koncept.

Jag vill också "varna" för att forumets design bygger väldigt mycket på höjden när man använder många separata [quote]- och [code]-taggar, så mina inlägg här ser meterlånga ut, men det är inte så mycket text som man kan tro.

De stilmässiga, officiella och generella riktlinjerna för Python är PEP-8. Det är lätt att tycka att "regler" på detta sätt är fåniga och främst i vägen, men de bygger ofta på erfarenheter av personer som kodat bra mycket längre än vi. Med erfarenhet så kommer man ofta själv på att reglerna är naturliga. Jag tyckte t ex att "4 blanksteg för indentering" istf tabbar var trams rätt länge, men efter några år så märkte jag att det var rätt bra ändå .

En överskuggande riktlinje är att det egentligen inte finns några "fel" vad gäller stil — bara "okunskap". Vet man varför reglerna finns så är det OK att ta beslutet att de bör frångås i enstaka fall där de inte gör saker bättre.

Skrivet av CarlKabul:

def print_i(msg, n=1): # Egen print-funktion med indentering för att slippa global indent-variabel

Python har en inbyggd speciell dokumentationssyntax för t ex funktioner, så kallade docstrings:

def print_i(msg, n=1): """Egen print-funktion med indentering för att slippa global indent-variabel"""

En radbrytning, indrag och tre citationstecken runt dokumentationssträngen, alltså. Detta gör att Python automatiskt kommer använda denna sträng som beskrivning av funktionen om t ex funktionen är definierad och en användare skriver `help(print_i)`. Det kan även hjälpa kodredigerarprogram, automatiskt dokumentationsgenerering, etc. Framför allt så är det det "naturliga" stället att hitta korta förklaringar av funktioner, klasser, metoder, etc.

Du har många "inline-kommentarer" (kommentarer på samma rad som kod). De ska enligt praxis försöka hållas till ett minimum. De försämrar snabbt läsbarheten om de är längre än ett ord eller två. Vi (iaf i västländer) är vana vid att läsa uppifrån och ner, från vänster till höger: en inlinekommenter gör att vi får två grupper av information på samma rad, och kommentaren är ofta intressantare att läsa innan koden. Dessutom kan det bli onödigt långa rader, vilket beroende på editor kan bli svårläst. Allmänt ska rader försökas hållas <80 tecken, av olika tekniska och historiska skäl.

Skrivet av CarlKabul:

print_i ("Kalenderprogram", 2)

Mellanslaget mellan `print_i` och parantesen ser udda ut. Dessutom används det inte konsekvent. Jag rekommenderar att alltid skippa detta (återigen enligt PEP-8, vilket jag antar bygger på matematiska konventioner för funktionsbegreppet).

Skrivet av CarlKabul:

print ("\n", end="")

Detta är bara ett invecklat sätt att skriva `print()`, vad jag kan se. `print()` utan argument skriver ut en blankrad. Även `print('')` gör detta, om man verkligen vill, men, tja.

Skrivet av CarlKabul:

print_i ("(1) Se denna månads kalender", 1)

Det är fritt att lägga till argumentet `1`, men samtidigt är det satt som "default"-argument till `print_i`, så om du utelämnar det andra argumentet till funktionen så händer samma sak som nu, men med mindre kod. Att ange mer information än nödvändigt är ofta onödigt, så jag skulle skippat det argumentet här (och på andra ställen).

Faktum är att du aldrig använder det andra argumentet till `print_i`, så du skulle helt kunna ta bort det i definitionen av funktionen utan att vara orolig (så länge du även tar bort alla onödiga argument när du kallar på funktionen).

Skrivet av CarlKabul:

resp = int(input(" {}: ".format(msg))) # Klamrarna lämnar utrymme för meddelandet (msg)

Denna typ av kommentar anser jag är helt rätt för dig att skriva nu, för att visa att du förstår programmets funktion. När man "kan" detta så bör man dock se till att kommentarer inte beskriver "uppenbara" saker, som t ex:

i += 1 # Lägger till 1 till i

och dylikt. Koden talar för sig själv, och sådana kommentarer är bara upprepande för någon med baskunskaper. Vad som är "baskunskap" och inte är svårt att kvantifiera, så det är lite luddigt. Känner man själv att man behöver dokumentation så är det bara att köra, givetvis, och det är lärorikt till en början.

Skrivet av CarlKabul:

# ------- Funktioner för felhantering/omstart av programmet -------

Dessa grupperingar tycker jag är bra för att visa hur du har insett hur funktioner ska representera logiska delar, och grupperar därefter.

Skrivet av CarlKabul:

def get_alternative(): # Skickar info om meddelande för val, tillåtet intervall samt intervallets felmeddelande till felhanteraren return get_int("Välj alternativ", [1, 2], "Ej giltigt alternativ") […] def get_run_again(): # Skickar info val för omstart resp. avslutning, tillåtet intervall samt intervallets felmeddelande till felhanteraren return get_int("(1) Kör programmet igen\n (2) Avsluta \n Ange val", [1, 2], "Ej giltigt alternativ")

Dessa två funktioner är snarlika i funktion, men du hanterar dem olika. I den första så skriver du ut valen i `main()` och frågar bara "Välj alternativ" i `get_int`. I den andra inkluderar `get_run_again()` valen. Så som `get_int` är uppbyggd så kommer alltså den andra funktionen generera hela meddelandet vid felinput, men den första bara "Välj alternativ:". För att illustrera vad jag menar:

(1) Se denna månads kalender (2) Ange år och månad Välj alternativ: 7 Fel: Ej giltigt alternativ. Försök igen! Välj alternativ:

kontra

(1) Kör programmet igen (2) Avsluta Ange val: 7 Fel: Ej giltigt alternativ. Försök igen! (1) Kör programmet igen (2) Avsluta Ange val:

Utan att värdera vilket som är "bäst", eller spekulera i att omorganisera koden, så borde de iaf bete sig på samma sätt. Användaren ska bli så lite överraskad som möjligt.

Skrivet av CarlKabul:

# -------- Hämtar automatisk uppgift om dagens datum --------- def today_year_month(): d = date.today() # Anropar "date" i "datetime" vid menyval 1 inYear = d.year inMonth = d.month return inYear, inMonth

Även här bör en "docstring" användas istf kommentaren innan funktionen.

Sedan ser jag att du gjort ett medvetet val (och medvetna val är inte "fel", som jag sa tidigare; bara okunskap är fel) att inte direkt skriva `return d.year, d.month`. Jag tycker att det vore klarare, och variabeltilldelningen känns lite onödig (minns att jag inte har några egentliga klagomål på koden, utan bara anstränger mig för att "klaga" på minsta lilla just nu ).

Skrivet av CarlKabul:

weekdayList = [[0, "Må", 6], [1, "Ti", 10], [2, "On", 14], [3, "To", 18], [4, "Fr", 22], [5, "Lö", 26], [6, "Sö", 30]]

"Listor i en lista" skulle inte vara mitt naturliga val för denna datatyp. Om du vill ha strängarna som index så skulle en dictionary med en tuple för varje index vara bättre. I detta fall så noterar jag dock att du överhuvudtaget inte använder varken index 0 eller index 1 i dina inre listor: du hade helt enkelt kunna skriva ovanstående som:

weekdayList = (6, 10, 14, 18, 22, 26, 30) […] # och sedan förenkla din enda användning av weekdayList till: print ("1".rjust(weekdayList[wDay]), end=" ")

Eller ah, nu förstår jag vad din offset i `weekdayList` är. Än smidigare än att hårdkoda dessa värden för veckodagarna som du gör nu vore att helt ta bort din `weekdayList` ur koden och i stället direkt skriva:

print ("1".rjust(6+wDay*4), end=" ")

…så slipper vi hela datatypsproblemet .

Skrivet av CarlKabul:

monthList = [[31, "januari"], [28+leapDay, "februari"], [31, "mars"], [30, "april"], [31, "maj"], [30, "juni"], [31, "juli"], [31, "augusti"], [30, "september"], [31, "oktober"], [30, "november"], [31, "december"]]

Här använder du däremot all data. En naturligare datatyp vore dock en tuple:

monthList = ((31, "januari"), (28+leapDay, "februari"), (31, "mars"), (30, "april"), (31, "maj"), (30, "juni"), (31, "juli"), (31, "augusti"), (30, "september"), (31, "oktober"), (30, "november"), (31, "december"))

Det spelar ingen roll i din vidare hantering i programmet (en tuple kallas på samma sätt som en lista). Paranteserna ger som sagt en tuple, som är en naturlig datatyp för statisk information. En lista inkluderar funktionalitet för att i efterhand ändras, dvs lägga till objekt, ändra deras värden, etc. Vi kommer troligen inte komma på fler månader fem rader längre ner i programmet, eller säga att juni har 31 dagar, så en tuple passar fint.

En tuple har en omärkbar prestandavinst mot en lista, men anledningen till att använda "rätt" datatyp är snarare att det visar att man har kontroll över språket. Det är bra att ha i ryggmärgen när man programmerar.

Skrivet av CarlKabul:

c = 0 while c < monthList[inMonth-1][0] : # Loop som räknar upp månadens dagar... c += 1 # ...med variabeln c

Eftersom du vet hur länge loopen ska köra så bör du använda en `for`-sats i stället: `for` är egentligen bara en förenkling av en `while`-loop där man automatiskt sätter en iterationsvariabel och avslutar den enligt ett förutbestämt kriterium. Dina tre rader ovan (ja, alla tre, utan andra ändringar) kan helt ekvivalent (men kortare, mer naturligt och därmed mer läsbart) skrivas:

for c in range(1, monthList[inMonth-1][0]+1):

Det extra "krånglet" med `(1, […]+1)` tillkommer för att c inte ska börja på 0. En annan lösning är att skriva

for c in range(monthList[inMonth-1][0]):

och modifiera dina `if`-satser för att ta hänsyn till att c kommer börja på 0, och du kommer behöva skriva ut `c+1` i din kalender.

Gällande din första `if`-sats inne i loopen så kommer den kontrolleras varje gång, men alltid bara köras första varvet. Du vet ju att alla månader börjar med sin första dag, så det hade inte behövt vara i loopen överhuvudtaget, utan skulle kunna ligga ovanför, och sedan ändra loopens villkor till:

for c in range(2, monthList[inMonth-1][0]+1):

Du kan också helt skippa din `if c > 1:`-kontroll: till att börja med så hade den lika gärna kunnat vara bara en `else:` till `if c == 1:`, för vi vet ju att c antingen är 1 eller större än 1. Om första dagens utskrift flyttas ovanför loopen så behövs `if c > 1:` inte alls, eftersom den alltid kommer vara sann.

Du skriver ibland typ:

Skrivet av CarlKabul:

print ("\n", " ", end="")

det vill säga med dubbla strängargument till `print()`. Det är onödigt här och gör det svårare att se vad som händer. `print()` lägger automatiskt till `sep` mellan strängarna, men ovanstående hade ekvivalent kunnat skrivas:

print ("\n ", end="")

vilket är kortare, men framför allt så ser man direkt hur slutsträngen kommer se ut, utan att behöva tolka in `sep`.

Skrivet av CarlKabul:

else : print ("\n") return

`while-else` är en ganska ovanlig konstruktion, och behövs sällan (t ex inte här). Din loop kommer stanna ändå enligt sitt krav, och du skulle kunna plocka bort `else` och minska indenteringen på nästa två kodrader, och programmet skulle fungera precis som nu. Du skulle även kunna plocka bort `return`, eftersom en funktion i Python returnerar automatiskt när den är "klar".

Nu var det inte mycket kvar att anmärka på, förutom:

Skrivet av CarlKabul:

# -------- Pseudokod --------

som inte är helt korrekt. "Pseudokod" är "låtsasprogramkod" som man använder för att göra en prototyp av ett program. Jag skulle kunna skriva pseudokod för att vispa grädde som:

bowl.add('vispgrädde') while bowl.whip(): if bowl.consistency == 'runny': continue elif bowl.consistency == 'firm': break else: print('Katten har ätit upp grädden!')

Det är alltså bara kod som "typ" är som riktig programkod, utan att skriva de faktiska funktionerna. Det är bara till för att beskriva en algoritm. Enbart uttrycket `main()` är inte pseudokod. Jag nämnde uttrycket tidigare för att själva `main()`-funktionens innehåll i Python ofta kan likna pseudokod om man gjort "rätt" tidigare i programmet, men det var ingen kommentar att hänga upp sig på . Ta helt enkelt bort din kommentarsrad om "Pseudokod" så ser det bättre ut.

Visa signatur

Nu med kortare användarnamn, men fortfarande bedövande långa inlägg.