Skrivet av zeem:
Det jag skulle vilja ha hjälp med är om jag definerar saker och ting rätt. Naming conventions, stor liten bokstav på lokala variabler alt globala t.ex _lokalVariabel globalVariabel.
PEP 8 är den vanligaste referensen för namngivning och liknande saker. Typiskt så ska variabler ha snake_case
och vara lokala: globala "variabler" ska undvikas, men däremot är det vanligt med globala "konstanter", som ju egentligen är precis samma sak, med enda skillnad att man per konvention inte ändrar dem efter att de väl satts. Sådana konstanter brukar namnges enligt SNAKE_CAPS
.
Bill du grotta ner dig i stilval i Python så är PEP 8 som länkades ovan en bra inkörsport. Vidare kan du börja titta på verktyg som pycodestyle
och Pylint och försöka förstå vad det är de klagar på i din kod. Kan också nämna Googles interna stilguide för Python som ofta fungerar bra att följa om man känner sig osäker. När man känner sig haj på dessa stilguider så brukar jag rekommendera föredraget Beyond PEP 8 av Raymond Hettinger som kan vara en ögonöppnare för vad som egentligen är mest viktigt när man programmerar.
Skrivet av zeem:
Skall jag kommentera koden mer? Brukar det vara mer kommentarer i börjar av programkoden?
Du bör använda så kallade "docstrings" för dina funktioner. Mer eller mindre alla dina nuvarande kommentarer skulle bättre fungera som docstrings, som då blir en mer officiell dokumentation över din kod. Det du skriver i en docstring exponeras sedan i som ett "magiskt" attribut på din själva funktion, och Python genererar automatiskt en vettig hjälptext åt din funktion om någon vill se en sådan.
Kommentarer som bara säger saker som "End of file", "Load modules", "Define classes", "Define constants", etc., är i mina ögon i stort sett alltid fullkomligt kontraproduktiva. Det är allt som oftast bländade uppenbart att det de beskriver händer enbart utifrån att titta på koden, och den enda effekten de kan ha på koden är att de säger emot vad som faktiskt står och därmed orsakar förvirring. Det är mycket bättre att helt enkelt följa vanliga konventioner för ett språk, vilket för en läsare gör det uppenbart att du i ett visst stycke exempelvis importerar moduler, osv.
Det kan låta överdrivet dramatiskt och negativt, men det går emot mycket av en absolut grundtanke i Python: läsbarhet genom att minimera visuellt brus och okonventionella överraskningar. När nu språket kämpat så för att bli av med exempelvis semikolon och måsvingar för att bli lättare att snabbt skanna av så ska man inte skjuta sig i foten genom att lägga in en massa icke-funktionella sektionsavgränsare i onödan. Det är inte Python.
(Citatet ska symbolisera första raden i din kod )
Börja gärna med en så kallad shebang för ett skript som ska kunna exekveras. Ett typexempel för Python 3:
Detta är bra på ett par olika sätt:
det ger tips till din editor att det är just Python 3 och inte Python 2 du skriver (även mänskliga läsare: jag vet egentligen fortfarande inte om koden är Python 2 eller Python 3 bara av att titta på ditt exempel, men jag gissar på 3 pga att du använder input
och har parenteser kring print
).
i de flesta operativsystem gör detta skriptet direkt exekverbart med rätt tolk. Detta gäller även Windows för de som sitter med exempelvis MSYS2 eller liknande *nix-lika miljöer.
Direkt efter din shebang bör man i Python-världen skriva en docstring för denna modul (ungefär "fil med Python-kod"). Det gör man enligt konvention genom att bara skriva en sträng avgränsad med trippla citationstecken:
#!/usr/bin/env python3
"""Perform arithmetic operations on user request."""
Skrivet av zeem:
#Functions for Arithmetic operations
def num_add(x, y):
result = x + y
return result
def num_sub(x, y):
result = x - y
return result
def num_mul(x, y):
result = x * y
return result
def num_div(x, y):
result = x / y
return result
Docstrings till dina funktioner, som sagt. Typiskt ska en docstring berätta vad funktionen gör samt beskriva in- och utparametrar. Ifall det är trivialt så brukar Python-communityt förespråka att skippa utläggningar om parametrarna, men det ska banne mig alltid vara en docstring som säger vad funktionen gör (OK, det finns ett fåtal fall där det går att välja bort (triviala "dunder"-funktioner, vanligen), men det är aldrig fel att ha en docstring).
Den översta kommentaren du har är rent krasst helt fel sätt att använda kommentarer . Om du känner att du behöver gruppera dessa funktioner så kanske de passar i en klass, där det du skrev som kommentar ovan passar utmärkt som en docstring till klassen i fråga.
I dessa triviala fall skulle jag skippa att mellanlagra resultatet innan retur.
Det finns ingen direkt poäng i att förkorta ord i funktions- och variabelnamn. Det är allt som oftast mer läsbart att inte behöva fundera på vad cnf_cc_abs
egentligen betyder.
Ett förslag som innefattar alla dessa idéer.
def add(x, y):
"""Return arithmetic sum of parameters."""
return x + y
def subtract(x, y):
"""Return arithmetic difference of parameters."""
return x - y
def multiply(x, y):
"""Return arithmetic product of parameters."""
return x * y
def divide(x, y):
"""Return arithmetic quotient of parameters."""
return x / y
eller om man vill gruppera funktionerna i en klass:
class Arithmetic:
"""Arithmetic operations."""
@staticmethod
def add(x, y):
"""Return arithmetic sum of parameters."""
return x + y
@staticmethod
def subtract(x, y):
"""Return arithmetic difference of parameters."""
return x - y
@staticmethod
def multiply(x, y):
"""Return arithmetic product of parameters."""
return x * y
@staticmethod
def divide(x, y):
"""Return arithmetic quotient of parameters."""
return x / y
Här använde jag dekoratorn @staticmethod
för att tydliggöra att funktionerna inte måste användas genom en instans av klassen, men det är inget att haka upp sig på. I detta fall kan jag tycka att klassen är överdriven — i Python ska man inte göra allting "objektorienterat" (i betydelsen "strössla klasser överallt") bara för att det går.
Skrivet av zeem:
#Function for entering the numbers that the user want to preform arithmetic operation on
def input_num():
num = float(input("Enter a number: "))
return (num)
Tidigare tips gäller. Ett tillägg vad gäller felhantering passar här: vad händer om användaren matar in fel sak? Typiskt bör du fånga detta och be om input igen. Funktionen bör inte returnera förrän den vet att den returnerar något vettigt.
Här kan det kanske också passa med en default-parameter för promptmeddelandet — dels för att göra funktionen mer generell (vilket inte måste vara en bra sak, om man nu inte behöver det), men också för att det kan göra koden mer läsbar där den anropas.
def float_input(prompt="Enter a number"):
"""Return floating point number from a user prompt."""
while True:
user_input = input('{}: '.format(prompt))
try:
return float(user_input)
except ValueError:
print("Invalid input.")
Skrivet av zeem:
#Fuction for printing the meny
def print_meny():
#Meny text for operation of calculator
print("What do you want to do?\n")
Håll dig konsekvent till engelska ("meny" → "menu").
Vi kan också notera att denna funktion jobbar med globala variabler. Detta är en styggelse — det gör kod mycket svårare att följa, och det är en ovana man bör stävja tidigt. När du börjar nå stadiet med att skriva tester för din kod så kommer du förbanna varje stund du tänkt "äsch, det är ju rätt smidigt med globala variabler ändå". Det är inte bra praxis. Försök se skillnaden mellan vad en global variabel och en så kallad global konstant är, och när en konstant faktiskt är passande.
Med funktionen ovan har du ett typexempel på en funktion som skulle kunna ta exempelvis en lista (egentligen vad som helt som går att "iterera" över — Python är inte så kinkigt gällande exakt vilken typ det är) med menyval som skrivs ut automatiskt.
Skrivet av zeem:
for each_meny in meny:
print(each_meny)
Jag skulle föredra en syntaxkonvention likt
for menu_item in menu_items:
dvs plural för samlingen av element och singular för iterationsvariabeln.
Att generera menyval passar sig också utmärkt för en standardfunktion i Python (det finns inte så många, så det är fullkomligt görbart att lära sig denna uppsättning) som heter enumerate
. Denna kommer ge dig ett ordningstal tillsammans med varje iteration, så att du slipper baka in menynumret i själva strängen som ska beteckna valet. Något i stil med:
for i, menu_item in enumerate(menu_items, start=1):
print('{}. {}'.format(i, menu_item))
Sannolikt så bör du även baka in din parsning av användarens input av menyval i samma funktion som den där du skriver ut menyvalen, för att ha kontroll över siffrorna. Det är möjligt att det är vettigt att splitta utskriften av hela menyn och inmatningen, men en användare av din funktion (t ex du själv där du vill få användaren att interagera med din meny) bör bara behöva göra ett funktionsanrop för att skriva ut menyn och få ett svar, kan jag tycka.
Vad gäller resten av programmet så håller jag med ovanstående talare om att huvudflödet ska logga i en funktion som heter main()
som du kallar på ifrån en if __name__ == "__main__"
-konstruktion. Detta är bra praxis av ett par olika anledningar som inte är helt lätta att se till en början, men dessa anledningar existerar definitivt: annars hade det inte varit praxis!
Kort sagt handlar det om att göra moduler importerbara utan att riskera märkliga sidoeffekter samt att hålla den globala namnrymden ren. Vill man mäta mikrosekunder så är variabelåtkomst av lokala variabler faktiskt också snabbare inne i en funktion än i den globala namnrymden, men det är inget direkt argument (dessutom kan overheaden för själva funktionsanropet potentiellt äta upp dessa mikrosekunder ändå).
Så, några summerande ord:
Använd docstrings.
Spana på de inbyggda funktionerna .
Undvik att ta in magiska parametrar bakvägen in i funktioner via globala variabler. Använder du explicita parametrar får du kod som är enklare att förstå, och inte minst enklare att testa.
"Brädgårdskommentarer" ska behöva användas mycket sparsamt. Docstrings (och logging
-utskrifter, vilket inte nämnts än) bör täcka de allra, allra flesta fall. Brädgårdskommentarer kan generellt hålla sig till tekniska detaljer över en viss implementation, som man tänker sig inte är uppenbar ens för en van Python-programmerare. Märk väl att detta inte betyder att man inte ska dokumentera sin kod — tvärtom! Men gör det med docstrings, bra variabelnamn, genomtänkt struktur och funktioner som är väl avgränsade i sitt ansvarsområde och någorlunda korta.