Good Programming Style (GPS) by Anne Lavergn
- Guidelines
- Naming:
- We must use descriptive file names for our Python programs, i.e., names that describe the purpose of each of our Python programs.
- We must use descriptive variable names, i.e., names that describe the purpose of each of our variables.
- We must use descriptive function names, i.e., names that describe the purpose of each of our functions.
- Comments:
- We must comment our code because comments allow people reading our programs to understand what our programs do. An easy way to do this is to transform the steps of our algorithm into comments.
- We must have a header comment block at the very top of our program file and this header comment block must contain
- the name of our program, i.e., the name of our file
- a description of our program
- the name of the author of our program -> us!
- the creation date of our program.
- User Interaction (or interface):
- When prompting the user, we must give her/him clear and unambiguous instructions: the value to enter, the format of this value (if possible) and any other useful information such as the range of the value, etc...
- The output the program produces must be labelled clearly.
- Readability:
- We must create Python programs that are easy to read. One way to do this is by putting an empty line between groups of statements or functions.
- Literal Values:
- We must not "hard-code" literal values into our program; "hard-coding" literal values does not lead to generalised (useful) solutions and it makes our programs difficult to modify.
- What do we mean by "hard-coding" literal values into a program? Here is an example:
- We would like our program to read data from the file
InputData.txt
. To do so, we must first open the file as follows:open("InputData.txt", "r")
in our program. Having written the name of the file as an argument in the call to the functionopen(..)
is what we call "hard-coding" a literal value. Here, the literal value is the actual name of the file, which we "hard-coded" as an argument into theopen(..)
function call.
- We would like our program to read data from the file
- Why does "hard-coding" literal values not lead to generalised solutions?
- What if we wanted to read from another data file?
- Why does "hard-coding" literal values make modifying our program difficult?
- If we wanted to read from another data file, we would need to modify our program. To do so, we would need to search our program (which may be quite large) for the file name of the old data file and when found, change it to the file name of the new data file. We would need to do this every time we found the old file name. In the process of doing so, we could make mistakes. For example, we could erroneously type the new file name somewhere in our program or miss one of the places where the old file name is used in our program. This is to say: modifying a program is an error-prone process.
- So, what could we do?
- Well, in order to reduce the possibility of such modification errors, we could assign this literal value representing the name of our data file to a descriptively named variable at the top of our program where we can easily find it. In this situation, the file name would be used only once in our program. So, no need to search for it. This would allow us to modify our program easily and quickly, hence reducing the probability of introducing errors in our program.
- But we would still have to modify our program every time we wanted our program to read data from a different file. To avoid having to make such modification at all, our program could prompt the user for the file name. This way, our program would be more generalised (useful) as it would be able to read any data files without requiring us to modify our programs.
- Code:
- We must not (as much as possible) repeat statements in our programs since repeated statements (code fragments) makes difficult to modify because one needs to make several times the same modification. In a nutshell, it is error-prone. Solution: encapsulate code fragment into a function.
- Functions:
- A function must perform one main (well-defined) action, i.e., it must have one purpose. Its name must define this main action or purpose.
- We must always include a
return
statement at the end of each of our functions, whether functions return a value. - A function must only have one (unique)
return
statement. However, multiple return statements are acceptable in ***recursive functions*** only.
- Global variables:
- We cannot make use of global variables. If a function needs the value of a variable defined either in the main part of our program or in another function, we must pass this variable as an argument to our function when we call it.
- Boolean Conditions:
- The conditions of our iterative statements and our conditional statements are not 1, 0, True or False.
- For example, we cannot write
while 1 :
while True :
while not 0 :
while not False :
False
, hence terminating the execution of the iterative statement (loop). The literal valuesTrue
,False
,1
and0
cannot be modified, so when we use them as illustrated above, we create infinite loops which require statements such asbreak
to terminate, but as we saw above, we cannot make use of these latter statements. - On the other hand, we can write this:
keepPlaying = True while keepPlaying: ... # player wants to stop playing keepPlaying = False
- For example, we cannot write
- The conditions of our iterative statements and our conditional statements are not 1, 0, True or False.
- Naming: