= "Hello World"
MyText print(MyText)
Hello World
In this tutorial you will learn the basics of python programming. Starting with the basic datatypes, if-else statements and loops and the usage of python functions.
< previous tutorial … next tutorial >
In the following we will have a look into the basics of python coding. Thereby we will focus mainly on topics that are relevant for python scripting with LIS Pro 3D. For general and fully-featured python tutorials, find a big number of sources on the web!
Take care that you have installed everything as described in the installation tutorial.
Create a new folder for your scripts called PYTHON_TUTORIAL and add a subfolder data, where you can put data in.
Search for the Miniforge Prompt and open it.
Miniforge is only a suggestion for these tutorials. You can use any other python package manager such as Anaconda, Miniconda, etc. or any python installation running without a package manager.
This will look like this:
Copy the path of your project folder (CTRL - C)
In Miniforge Prompt type cd + space and right-click after the space in order to paste the path you have copied. Type Enter!
Thereby you change your current directory to the project directory
Initially you are in the (base) environment of conda. Type conda activate environmentName in order to use your own environment with all the installed modules (see installation tutorial)! Type Enter!
In this case the environment is called (myenv). On the left side you can see that we are in the (myenv) environment now.
Note, that after this switch, the current working directory is still the same. But you now have access to the python packages that you have installed in your environment (myenv)!!
Note, that you can have different environments running, with completely different installed modules and different versions!
Type code + space + . in order to start Visual Studio Code from the project directory (the current directory). Type Enter!
Visual Studio Code will open
In case you are asked if you trust the authors of what you are trying to open, click ok
If Visual Studio Code is open, it should look like this
Find the EXPLORER in the upper-left section of VSCode. You can see that you are in your project folder and that you have one subfolder called data. You have no scripts yet.
Click onto the New File Button in order to add a new script. Call the script MyScript.py.
After that, the script MyScript.py is listed in your working directory.
If the script is selected, you can see it as one tab of the code editor and inspect its content. In the moment, we have one empty script!
Before we start coding, please check if the correct python installation (the one of your environment (myenv)) is also used by VSCode
Check this at the beginning of every coding session. Especially, if you have multiple environments, with different modules installed.
Type ctrl + shift + P to go to the following drop-down menu:
Click on Python: Select Interpreter!
Here, the python installation of your environment (myenv) should be shown and should be selected. If not, add the correct path (see installation tutorial).
If everything is set correctly here, we can start scripting.
Type the following command into the first line of your script:
print("Hello World")
and press the play/run button in the upper-right corner of the screen
At the bottom of the screen, you can see the TERMINAL. After Execution, it is indicated that the script c:/LiDAR_Data/PYTHON_TUTORIAL/MyScript.py was executed.
And it prints: Hello World. Because we have told python to print “Hello World”.
Try out some other text to be printed and run the script again!
“Hello World” is a piece of text. In python, it is an object of type string. In short, a string is a sequence of characters enclosed in quotation marks.
print() is a built-in function used to display data, such as the string “Hello World” to the console or standard output stream. Thereby it serves as a means for the computer (Python program) to convey information or messages to the user by displaying text or data on the screen, allowing for interaction and information exchange between the user and the program.
In python we can store an object like a string (e.g. “Hello World”) in a variable. A variable in programming is a symbolic name or identifier that represents a value or data storage location in a computer program (in our case it has to represent a string).
Let’s define a new variable with the name MyText. If we print this variable, we will see that it points onto a string with 11 characters: “Hello World”.
= "Hello World"
MyText print(MyText)
Hello World
Let’s check, if “Hello World” is actually a string.
Use the build-in function type(), which is returning the type of the variable MyText. We can store the returned value in a variable again. Let’s call the variable type_returned.
If you define new variables, you can give them any name you want, except for keywords that are already in use by python. If you would call the returned value simply type you would override the built-in function type(). If you have accidentaly chosen a name that is already in use, it will be indicated in a different color in VSCode
= "Hello World"
MyText = type(MyText)
type_returned
print(type_returned)
print(MyText)
<class 'str'>
Hello World
After printing type_returned, we have verified that the variable type is a ‘str’!
As a string is a sequence of characters, we can access the number of characters by using the built-in function len().
= "Hello World"
MyText = len(MyText)
length print(length)
11
You can see that “Hello World” has 11 characters in it. One of the characters is a space!
As a string is a sequence of characters, we can access the individual characters by an index in rectangular brackets: MyText[0]
Note that the indices of the individual characters start with 0!
= "Hello World"
MyText
print(MyText[0])
print(MyText[1])
print(MyText[2])
print(MyText[3])
print(MyText[4])
print(MyText[5])
print(MyText[6])
print(MyText[7])
print(MyText[8])
print(MyText[9])
print(MyText[10])
H
e
l
l
o
W
o
r
l
d
In this code the script prints the individual characters one after another.
Note that character 5 is no letter here, but a space (which is also a character)!
= "Hello World"
MyText
print(MyText[:5]) # access all characters before the character with index **5**
print(MyText[5:]) # access all characters after the character with index **5** (including character 5)
Hello
World
Check what happens if you add or multiply strings
= MyText + MyText + MyText
Sum = MyText * 5 Product
= "Hello World"
MyText
= MyText + MyText + MyText
Sum = MyText * 5
Product
print(Sum)
print(Product)
Hello WorldHello WorldHello World
Hello WorldHello WorldHello WorldHello WorldHello World
You can see that you can use addition and multiplication for a string in order to concatenate it!
= " "
Space = "Hello"
Text0 = "my"
Text1 = "name"
Text2 = "is"
Text3 = "Python!"
Text4
= Text0 + Space + Text1 + Space + Text2 + Space + Text3 + Space + Text4
Sentence
print(Sentence)
Hello my name is Python!
Add an “\n” character and check what it does!
= "\n"
n = " "
Space = "Hello"
Text0 = "my"
Text1 = "name"
Text2 = "is"
Text3 = "Python!"
Text4
= Text0 + n + Text1 + Space + Text2 + Space + Text3 + Space + Text4
Sentence
print(Sentence)
Hello
my name is Python!
The “\n” character represents a new line statement.
If we can concatenate any combination of characters as a string, we can also create filepaths.
This is an example filepath:
We could just write:
= "C:\Users\Public\Downloads"
path print(path)
But as you already know, the \ character can easily be interpreted as \n if by chance an n is occuring next to it. Additionally, the separator is interpreted differently when using different operating systems.
Thus we let a python module called os (operating system) help us with it.
We have already seen that python has some built-in functions that help us doing things (type(), len(), print()). For more specific tasks we need additional modules. One of these modules is the module called os for solving problems related to the operating system and filepaths. Let’s import this module in our python script.
Imports are always made at the very top of the script!
import os
import os
= "C:" + os.sep + "Users" + os.sep + "Public" + os.sep + "Downloads"
path print(path)
C:\Users\Public\Downloads
This is the easiest way to define a path
Using os, we can also query the current working directory and get it as a string
import os
= os.getcwd()
cwd print(cwd)
But we can also write it manually:
import os
= path = "C:" + os.sep + "LiDAR_Data" + os.sep + "PYTHON_TUTORIAL"
cwd print(cwd)
C:\LiDAR_Data\PYTHON_TUTORIAL
Using os we can check if the given path really exists. Therefore we can use the function os.path.exists(), which receives the string to be checked and returns a so called bool. A bool can only represent two value: either True or False. Thus we have learned a new data type, called bool. It can have only two values: True or False!
import os
= path = "C:" + os.sep + "LiDAR_Data" + os.sep + "PYTHON_TUTORIAL"
cwd = os.path.exists(cwd)
PathExists print(PathExists)
print(type(PathExists))
True
<class 'bool'>
In this case the cwd must exist (the variable PathExists has the value True), because it is the current working directory. However, it becomes more interesting, if we check for the existance of subfolders.
You can see, that we have a subfolder called data in our cwd:
You can also see it in the EXPLORER of VSCode.
Lets define the subfolder as a string and check, if it exists.
import os
= os.getcwd()
cwd
= cwd + os.sep + "data"
path
= os.path.exists(path)
PathExists print(PathExists)
True
Lets define a subfolder that is not existing:
import os
= os.getcwd()
cwd
= cwd + os.sep + "processing"
path
= os.path.exists(path)
PathExists print(PathExists)
False
Using os we can create new folders, if the queried paths are not existing. Therefore we can use the function os.makedir(), which receives the path to be created and creates the desired path in our filesystem.
We can use a so-called if-statement in order to check, if the path is not already existing, or more specific, if the variable PathExists == False. An if-statement always consists of an if, a statement and ends with a colon. Everything that has to be performed by the program, if the statement is true, has to be indented one level.
In an if-statement always use == instead of =. = sets a value for a variable, == compares two values!
import os
= os.getcwd()
cwd
= cwd + os.sep + "processing"
path = os.path.exists(path)
PathExists
if(PathExists == False):
os.makedirs(path)
You can see that the path is now existing:
Let’s create some new folders and subfolders!
import os
= os.getcwd()
cwd
= cwd + os.sep + "processing"
path
= path + os.sep + "01_raster"
raster = path + os.sep + "02_shapes"
shapes = path + os.sep + "03_point_clouds"
pointclouds
= cwd + os.sep + "export"
export
if not os.path.exists(path):
os.makedirs(path)
if not os.path.exists(raster):
os.makedirs(raster)if not os.path.exists(shapes):
os.makedirs(shapes)if not os.path.exists(pointclouds):
os.makedirs(pointclouds)
if not os.path.exists(export):
os.makedirs(export)
In this example we use if not instead of if, which is simply the opposite statement.
Again, we can see that the defined paths have been generated in our cwd:
Note that manipulating filepaths as described above is a helpful method in order to manage multiple files with varying filenames in an automation pipeline!
Until now we have hardcoded the string within our script. Now we want to have a dynamic input by the user. Write the following code:
= input("Hello\nPlease provide a short text! ")
Sentence print(Sentence)
If you run this script, in the TERMINAL you will see the following Prompt:
Click with your left-mouse onto the white cursor at the end of the statement
Write a text
Enter
You can see that the script prints the text that we have provided.
input() is a built-in function used to collect user input from the keyboard. When input() is called, it displays a prompt to the user and waits for them to enter text. Once the user enters his/her input and presses the Enter key, the entered text is returned as a string by the input() function. The string is stored in the variable sentence and passed to the built-in function print() which is displaying the string in the console.
Now we are able to recieve some input data from outside of the script, do something with it and generate a user output (print)
Now let’s ask the user a question and tell him/her if the answer was correct or not. Therefore we have two cases that could occur. Either the answer is correct (then we want to print “correct”) or the answer is wrong (then we want to print “incorrect”)
This can be done, using the if and else statements.
= input("Hello\nWhat is the first letter in the alphabet! ")
Answer
if Answer == "A":
print("correct")
else:
print("incorrect")
An if-statement starts with if, followed by a condition and ends with “:”. Everything that has to be executed, if the given condition is true, has to be indented one level
The else-statement statement is the counterpart of the if and also ends with “:”. Everything that has to be executed, if the given condition is not true, has to be indented one level
In Python, indentation plays a crucial role in determining the structure and grouping of code, e.g. defining code blocks like if-else statements. Unlike many other programming languages that use braces or other symbols to denote code blocks, Python uses indentation for this purpose.
Note that “==” is a comparison, checking if two values are equal. A single “=” is always an assignment of a value to a variable. It is not allowed to put a single “=” into an if-statement, and you will get an error!
You can make an assignment and a comparison in one line, if you assign the result of the comparison to a variable.
= input("Hello\nWhat is the first letter in the alphabet! ")
Answer = Answer == "A"
result print(result)
print(type(result))
If we print the value of the variable result. You can see that it is either True or False. Thus it is a bool again. It can have only two values: True or False!
We can change the code of our quiz as follows:
= input("Hello\nWhat is the first letter in the alphabet! ")
Answer
= Answer == "A"
result print(result)
if (result == True):
print("correct")
else:
print("incorrect")
In the moment we have the possibility that the user types in ether a lower case or an upper case letter. Lets check if the letter is “A” and if the letter is upper case.
We can change the code of our quiz as follows and use an and-statement:
= input("Hello\nWhat is the first letter in the alphabet! ")
Answer
= Answer == "A" and Answer.isupper == True
result print(result)
if (result == True):
print("correct")
else:
print("incorrect")
Note that the result is now only true, if both conditions are true! E.g. F would be an uppercase letter, but is not identical with “A”!
But in or case this is not very helpful and does not improve our code a lot. What we want to do instead is to be more tolerant and allow the user to type in both the lower case and the upper case letter of “A”. Therefore we use an or-statement:
= input("Hello\nWhat is the first letter in the alphabet! ")
Answer
= Answer == "A" or Answer == "a"
result print(result)
if (result == True):
print("correct")
else:
print("incorrect")
Note that the result is now true, if at least one of both options is true! “A” or “a”!
Let’s give the user four suggestions (A,B,C,D) in order to decide, which is the correct solution. Therefore we can use the elif (else if) statement additionally:
= input("Hello\nWhat is the first letter in the alphabet? A, B, C or D")
Answer
if Answer == "A" or Answer == "a":
print("correct")
elif Answer == "B" or Answer == "b":
print("incorrect")
elif Answer == "C" or Answer == "c":
print("incorrect")
elif Answer == "D" or Answer == "d":
print("incorrect")
else:
print("answer was not available for selection")
We have already used the module called os. Additional modules are the module called math for math operation (square root, round, cos, sin, tan…) and the module called random in order to generate pseudo-random numbers.
Import the math module and the random module!
import math
import random
Lets implement a math quiz for the multiplication of values between 1 and 10, e.g. 3*6 = 18.
First generate two random numbers between 1 and 10 using the random.uniform() function of the random module
import math
import random
= random.uniform(1, 10)
Value1 = random.uniform(1, 10) Value2
import math
import random
= random.uniform(1, 10)
Value1 = random.uniform(1, 10)
Value2
print(Value1)
print(Value2)
print(type(Value1))
print(type(Value2))
5.153774961125492
9.208627557392852
<class 'float'>
<class 'float'>
You can see that the function random.uniform generates a decimal number between 1 and 10. Value1 and Value2 are both decimal numbers and 13 decimal places get printed.
In python these numbers are represented as floating point numbers. A floating point number is another datatype in python. If we query the datatype, we see that it is simply called float.
It is no surprise, that we can make calculations with the given floating point values.
import math
import random
= random.uniform(1, 10)
Value1 = random.uniform(1, 10)
Value2
= Value1 + Value2
Sum = Value1 - Value2
Difference = Value1 * Value2
Product = Value1 / Value2
Quotient
print("Values: ", Value1, Value2)
print("Sum: ", Sum)
print("Difference: ", Difference)
print("Product: ", Product)
print("Quotient: ", Quotient)
Values: 7.869231722805392 6.255919592749745
Sum: 14.125151315555136
Difference: 1.6133121300556468
Product: 49.22928091458608
Quotient: 1.2578856882887983
Note that the built-in function print() can take multiple arguments in order to print multiple values! In the first print-statement we print one string (“Values:”), a float (Value1) and another float (Value2).
Note also that there is a difference between “Sum:”, which is a string and will be printed as text, and Sum (without quotation marks), which is the variable name for a float and the assigned decimal number will be printed!
If you want to use a variable (e.g. Sum) for e.g. a print-statement, it has to be defined before. Take care of lower and upper case.
If we remember that we wanted to make a primary school math quiz, which can be done by calculating in our heads. Calculations with decimal numbers might be too difficult. Thus we want to round the given numbers.
Round the values to only 2 digits by using the build-in function round(). The function takes two arguments: the variable value to be rounded and the number of decimals we want to round to.
import math
import random
= random.uniform(1, 10)
Value1 = random.uniform(1, 10)
Value2
= round(Value1,2)
Value1 = round(Value2,2)
Value2
= Value1 * Value2
Product
print("Values: ", Value1, Value2)
print("Product: ", Product)
Values: 8.31 8.33
Product: 69.2223
Note that we use the same variable name as an argument for the round() function but also for the returned result. Thereby, we overwrite the original value of the variable!
You can see that we now have only 2 instead of 15 decimal positions.
Let’s round to the nearest integer by setting the decimals parameter to 0
import math
import random
= random.uniform(1, 10)
Value1 = random.uniform(1, 10)
Value2
= round(Value1,0)
Value1 = round(Value2,0)
Value2
= Value1 * Value2
Product
print("Values: ", Value1, Value2)
print("Product: ", Product)
Values: 8.0 1.0
Product: 8.0
Now, you can see that we were successful and the decimal places are zero. However, one decimal place is still shown here, which shows us that python still interpretes this value as float, although it obviously has been rounded to the nearest integer.
In order to let python know, that our values have to be interpreted as integers we have to cast the variable to an integer using int().
import math
import random
= random.uniform(1, 10)
Value1 = random.uniform(1, 10)
Value2
= round(Value1,0)
Value1 = round(Value2,0)
Value2
= int(Value1) #casting to integer
Value1 = int(Value2) #casting to integer
Value2
= Value1 * Value2
Product
print("Values: ", Value1, Value2)
print("Product: ", Product)
Values: 7 3
Product: 21
Now we have two integers created and python prints the given values without decimals now. int is an additional datatype in python and we can calculate with it. Integers are perfect for enumerations, representing the number of objects. It can also be used as an index to access individual entries in a sequence like a string
The len() function returns an int as it describes the number of entries. If we use string[i] to get an individual character from a string, i has to be an int.
Again we use the same variable name as an argument for the int() function but also for the returned result. Thereby, we overwrite the original value of the variable! In this case the datatype of the variable is changing from float to int!
You can switch into any datatype if it makes sense (str(), float(), bool())!
Try to change the values to string (str())! Can you explain, what is happending here? Why is an addition working and a multiplication not?
import math
import random
= random.uniform(1, 10)
Value1 = random.uniform(1, 10)
Value2
= round(Value1,0)
Value1 = round(Value2,0)
Value2
= str(Value1)
Value1 = str(Value2)
Value2
= Value1 + Value2
Sum
print("Values: ", Value1, Value2)
print("Sum: ", Sum)
Values: 2.0 1.0
Sum: 2.01.0
import math
import random
# first let python pre-calculate a math problem
= random.uniform(1, 10)
Value1 = random.uniform(1, 10)
Value2 = round(Value1,0)
Value1 = round(Value2,0)
Value2 = int(Value1)
Value1 = int(Value2)
Value2
= Value1 * Value2
Product
# let's formulate a question
= "Hello\nWhat is the product of " + str(Value1) + " and " + str(Value2) + "? "
Question
= input(Question)
Answer
# the Answer is initially a string and has to be converted into an integer before comparison
= int(Answer)
Answer
if Product == Answer:
print("Perfect, this was correct!")
else:
print("Sorry, this was incorrect! The result is: ", Product)
To make the quiz more challenging, let’s measure the elapsed time for an answer.
Therefore we use the python module time
import time
# Record the start time
= time.time()
start_time
# Perform some operations
# ...
# Record the end time
= time.time()
end_time
# Calculate the elapsed time
= end_time - start_time elapsed_time
Let’s add this to our math quiz:
import math
import random
import time
# Record the start time
= time.time()
start_time
# first let python pre-calculate a math problem
= random.uniform(1, 10)
Value1 = random.uniform(1, 10)
Value2 = round(Value1,0)
Value1 = round(Value2,0)
Value2 = int(Value1)
Value1 = int(Value2)
Value2
= Value1 * Value2
Product
# let's formulate a question
= "Hello\nWhat is the product of " + str(Value1) + " and " + str(Value2) + "? "
Question
= input(Question)
Answer
# the Answer is initially a string and has to be converted into an integer before comparison
= int(Answer)
Answer
# Record the elapsed time
= time.time()
current_time = int(current_time - start_time)
elapsed_time
if Product == Answer:
print("Perfect, this was correct!")
print("You made it in ", elapsed_time, " seconds")
else:
print("Sorry, this was incorrect! The result is: ", Product)
print("Maybe too quick, (you made it in ", elapsed_time, " seconds)")
As you have noticed, in the moment we are only able to ask a single question, evaluate it and show the results. Thereby python interpretes each line of written code one after the other, if the code has finished also python finishes the program.
But how can we ask multiple questions? Let’s tell python to repeat a part of the code until a certain criterion is given. This can be done by the while(): statement. It takes a bool-argument, which usually is the result of a comparison. while(this is true): do this, else, stop. The while():-statement ends with a “:” and everything that has to be done, when the argument is true, has to be indented as code block.
In our case we can use the elapsed time to control the while statement
= time.time()
start_time = 30 # only run 30 seconds
stop_time = 0
elapsed_time
while(elapsed_time < stop_time):
# Do something
= time.time()
current_time = int(current_time - start_time) elapsed_time
Adapt this for our quiz:
import math
import random
import time
# Record the start time
= time.time()
start_time
#Set stopwatch
= 30 # only run 30 seconds
stop_time = 0
elapsed_time
while(elapsed_time < stop_time):
# first let python pre-calculate a math problem
= random.uniform(1, 10)
Value1 = random.uniform(1, 10)
Value2 = round(Value1,0)
Value1 = round(Value2,0)
Value2 = int(Value1)
Value1 = int(Value2)
Value2
= Value1 * Value2
Product
# let's formulate a question
= "What is the product of " + str(Value1) + " and " + str(Value2) + "? "
Question
= input(Question)
Answer
# the Answer is initially a string and has to be converted into an integer before comparison
= int(Answer)
Answer if Product == Answer:
print("Perfect, this was correct!")
else:
print("Sorry, this was incorrect! The result is: ", Product)
# Record the elapsed time
= time.time()
current_time = int(current_time - start_time) elapsed_time
The program will repeat asking for 30 seconds and the user can try to be fast in answering the questions. This is nice but it would be great, if we could just ask the questions and the user gets an overall result for this quiz. It would be interesting to have the total number of asked questions, the number of correct answers and so on.
Therefore, we have to remember that everything, which is indented within the while loop is repeated until the given stop criterion evaluates to False.
Thus, before the loop, we can define an integer called i and assign the value 0. In the while loop we can then increase the value of i by 1 (Note, this is a counter). Additionally, we could have a second counter that only is incremented when the given answer was correct.
import math
import random
import time
# Record the start time
= time.time()
start_time
#Set stopwatch
= 30 # only run 30 seconds
stop_time = 0
elapsed_time
#Define counters
= 0
i = 0
i_correct = 0
i_incorrect
while(elapsed_time < stop_time):
# first let python pre-calculate a math problem
= random.uniform(1, 10)
Value1 = random.uniform(1, 10)
Value2 = round(Value1,0)
Value1 = round(Value2,0)
Value2 = int(Value1)
Value1 = int(Value2)
Value2
= Value1 * Value2
Product
# let's formulate a question
= "What is the product of " + str(Value1) + " and " + str(Value2) + "? "
Question
= input(Question)
Answer
# the Answer is initially a string and has to be converted into an integer before comparison
= int(Answer)
Answer if Product == Answer:
# increase the value of i_correct by 1
+=1
i_correctelse:
# increase the value of i_incorrect by 1
+=1
i_incorrect
# Record the elapsed time
= time.time()
current_time = int(current_time - start_time)
elapsed_time
# increase the value of i by 1
+=1
i
# print the results of the quiz after the time is over
print("")
print("#### Your Results ####")
print("Correct Answers: ", i_correct)
print("Incorrect Answers: ", i_incorrect)
print("Total Answers: ", i)
print("Score: ", (i_correct/i)*100)
It might be convenient for the user to abort the quiz before it is actually over. Let’s use “Q” for quitting the quiz and “S” for skipping the question.
Therefore we can use the break and the continue statement. Break will stop the loop and python will interprete the next code line, which is not indented within the while-loop. Continue will only jump to the top of the while loop code again and skip the rest of the code within the while-code-block.
if Answer == "Q" or Answer == "q":
break
if Answer == "S" or Answer == "s":
continue
This has to be evaluated, before the answer has been converted to integer, because both “Q” and “S” can’t be converted to integer!
import math
import random
import time
# Record the start time
= time.time()
start_time
#Set stopwatch
= 30 # only run 30 seconds
stop_time = 0
elapsed_time
#Define counters
= 0
i = 0
i_correct = 0
i_incorrect
print(" ")
print("#### Welcome to the Quiz ####")
print("Type S to skip the question")
print("Type Q to quit the quiz")
print(" ")
while(elapsed_time < stop_time):
# first let python pre-calculate a math problem
= random.uniform(1, 10)
Value1 = random.uniform(1, 10)
Value2 = round(Value1,0)
Value1 = round(Value2,0)
Value2 = int(Value1)
Value1 = int(Value2)
Value2
= Value1 * Value2
Product
# let's formulate a question
= "What is the product of " + str(Value1) + " and " + str(Value2) + "? "
Question
= input(Question)
Answer
## allow the user to quit or skip
if Answer == "Q" or Answer == "q":
+=1
ibreak
if Answer == "S" or Answer == "s":
+=1
icontinue
# the Answer is initially a string and has to be converted into an integer before comparison
= int(Answer)
Answer if Product == Answer:
# increase the value of i_correct by 1
+=1
i_correctelse:
# increase the value of i_incorrect by 1
+=1
i_incorrect
# Record the elapsed time
= time.time()
current_time = int(current_time - start_time)
elapsed_time
# increase the value of i by 1
+=1
i
# print the results of the quiz after the time is over
print("")
print("#### Your Results ####")
print("Correct Answers: ", i_correct)
print("Incorrect Answers: ", i_incorrect)
print("Total Answers: ", i)
print("Score: ", (i_correct/i)*100)
Our quiz runs for a defined period of time and counts the number of answered questions. But we could also do it the other way around and define a number of questions and measure the elapsed time the user has needed to answer these questions.
This can be done with a for-loop instead of a while-loop. A For-loop includes an iterator which is incremented by (e.g.) 1 in each iteration of the loop.
for i in range(1,11):
This loop performs exactly 10 iterations. It starts with index 1 and ends with index 10 (1 before 11).
Note that the variable i is defined within this loop and replaces our own definition of i as a counter! Thus we should not increment the counter i by ourselves as we did in the code above (i+=1)!
import math
import random
import time
# Record the start time
= time.time()
start_time
#set number of questions
= 11
num_questions
#Set stopwatch
= 0
elapsed_time
#Define counters
= 0
i_correct = 0
i_incorrect
print(" ")
print("#### Welcome to the Quiz ####")
print("Type S to skip the question")
print("Type Q to quit the quiz")
print(" ")
for i in range(1,num_questions):
# first let python pre-calculate a math problem
= random.uniform(1, 10)
Value1 = random.uniform(1, 10)
Value2 = round(Value1,0)
Value1 = round(Value2,0)
Value2 = int(Value1)
Value1 = int(Value2)
Value2
= Value1 * Value2
Product
# let's formulate a question
= "What is the product of " + str(Value1) + " and " + str(Value2) + "? "
Question
= input(Question)
Answer
if Answer == "Q" or Answer == "q":
break
if Answer == "S" or Answer == "s":
continue
# the Answer is initially a string and has to be converted into an integer before comparison
= int(Answer)
Answer if Product == Answer:
# increase the value of i_correct by 1
+=1
i_correctelse:
# increase the value of i_incorrect by 1
+=1
i_incorrect
# Record the elapsed time
= time.time()
current_time = int(current_time - start_time)
elapsed_time
= int(current_time - start_time)
total_time # print the results of the quiz after the time is over
print("")
print("#### Your Results ####")
print("Elapsed Time: ", total_time)
print("Correct Answers: ", i_correct)
print("Incorrect Answers: ", i_incorrect)
print("Total Answers: ", i)
print("Score: ", (i_correct/i)*100)
Note that we also measure the total_time now after the loop has finished (not indented within the for-loop)!
In the moment we only have a look onto the overall score, but not on all the questions in detail. An additional feature for the quiz would be a detailed overview with all the asked questions and all the answers besides the overall score.
In order to have an overall print of all the questions and answers at the end of the quiz, we need to have a possibility to remember all of this information and recall this memory in the end.
Keep in mind that python interpretes the code line by line. If one line has been executed, it is gone. Thus, we need an object, where we can store this information as a sequence, and recall its information after the for-loop has finished.
Let’s use a python list, which is a sequential datatype like a string, but it cannot only store a sequence of characters but a sequence of all available python datatypes.
The objects within the list are enclosed in square brackets.
## a list with many different datatypes
# a string
# an int
# a float
# a bool
# a list (within a list)
= ["Hello", 1, 3.89, True, [1,2,3]] MyList
A list can have a dynamic length. We can define a variable MyList and assign an empty list to it. Later, we can append elements to the list one by one using the append-method of the list. See the following code:
= []
MyList print(len(MyList))
"Hello")
MyList.append(1)
MyList.append(3.89)
MyList.append(True)
MyList.append(1,2,3])
MyList.append([
print(MyList)
print(len(MyList))
0
['Hello', 1, 3.89, True, [1, 2, 3]]
5
Initially, we have a list with 0 entries. Note that we fill up the list step by step and in the end it has 5 entries!
We can use lists to store information and recall it at a later time!
Thus, we could use lists in order to remember the different questions and answers of our quiz. This is an idea how it could work:
= []
QuestionList
for i in range(1,6):
= "What is the product of 3 and 4"
Question = 15
Answer = False
Result # ask and process question
= [Question,Answer,Result]
Summary
QuestionList.append(Summary)print(QuestionList)
[['What is the product of 3 and 4', 15, False], ['What is the product of 3 and 4', 15, False], ['What is the product of 3 and 4', 15, False], ['What is the product of 3 and 4', 15, False], ['What is the product of 3 and 4', 15, False]]
In this code we create a new empty list called QuestionList. After getting the question and answer (which is always incorrect here, indeed) we create a list called Summary including the question (string), the answer (int) and the result (bool). In each iteration and for each question the summary is appended to the QuestionList
We print the list after all questions have finished and you can see that QuestionList is a list containing 5 summary lists now.
The whole list is printed in a single line which is a bit messy. Let’s print the individual entries of QuestionList one after another!
Therefore we can use a for-loop again that increments the variable i by starting with 0 and ending with the result of len(QuestionList) (the total number of entries within the list). We can use the incremented index i in order to access the individual entries of QuestionList (QuestionList[i]).
= []
QuestionList
for i in range(1,6):
= "What is the product of 3 and 4"
Question = 15
Answer = False
Result # ask and process question
= [Question,Answer,Result]
Summary
QuestionList.append(Summary)
for i in range(0, len(QuestionList)):
print(QuestionList[i])
['What is the product of 3 and 4', 15, False]
['What is the product of 3 and 4', 15, False]
['What is the product of 3 and 4', 15, False]
['What is the product of 3 and 4', 15, False]
['What is the product of 3 and 4', 15, False]
You can see that now the entries are printed one after another.
Note that there is also a shorter version for iterating through the QuestionList!
for entry in QuestionList:
print(entry)
This type of for-loop provides the same result, but avoids to use an iterator and directly returns the entry of the list that we want to have. Thus we don’t have to use the iterator anymore in order to access the individual entries (QuestionList[i])
Let’s print also the different entries of the summary list separately:
= []
QuestionList
for i in range(1,6):
= "What is the product of 3 and 4"
Question = 15
Answer = False
Result # ask and process question
= [Question,Answer,Result]
Summary
QuestionList.append(Summary)
for entry in QuestionList:
print(entry[0],entry[1],entry[2])
What is the product of 3 and 4 15 False
What is the product of 3 and 4 15 False
What is the product of 3 and 4 15 False
What is the product of 3 and 4 15 False
What is the product of 3 and 4 15 False
Let’s wrap the whole result into a nice text again using string-concatenation:
= []
QuestionList
for i in range(1,6):
= "What is the product of 3 and 4"
Question = 15
Answer = False
Result # ask and process question
= [Question,Answer,Result]
Summary
QuestionList.append(Summary)
for entry in QuestionList:
= "Question: " + entry[0] + ", Answer: " + str(entry[1]) + ", Result: " + str(entry[2])
SummaryString print(SummaryString)
Question: What is the product of 3 and 4, Answer: 15, Result: False
Question: What is the product of 3 and 4, Answer: 15, Result: False
Question: What is the product of 3 and 4, Answer: 15, Result: False
Question: What is the product of 3 and 4, Answer: 15, Result: False
Question: What is the product of 3 and 4, Answer: 15, Result: False
Let’s integrate this idea into our script:
import math
import random
import time
# Record the start time
= time.time()
start_time
#set number of questions
= 11 # only run 30 seconds
num_questions
#Set stopwatch
= 0
elapsed_time
#Define counters
= 0
i_correct = 0
i_incorrect
print(" ")
print("#### Welcome to the Quiz ####")
print("Type S to skip the question")
print("Type Q to quit the quiz")
print(" ")
= []
QuestionList for i in range(1,num_questions):
# first let python pre-calculate a math problem
= random.uniform(1, 10)
Value1 = random.uniform(1, 10)
Value2 = round(Value1,0)
Value1 = round(Value2,0)
Value2 = int(Value1)
Value1 = int(Value2)
Value2
= Value1 * Value2
Product
# let's formulate a question
= "What is the product of " + str(Value1) + " and " + str(Value2) + "? "
Question
= input(Question)
Answer
if Answer == "Q" or Answer == "q":
break
if Answer == "S" or Answer == "s":
continue
# the Answer is initially a string and has to be converted into an integer before comparison
= int(Answer)
Answer
= False
Result if Product == Answer:
= True
Result +=1
i_correctelse:
+=1
i_incorrect
# Record the elapsed time
= time.time()
current_time = int(current_time - start_time)
elapsed_time
= [Question,Answer,Result]
Summary
QuestionList.append(Summary)
= int(current_time - start_time)
total_time # print the results of the quiz after the time is over
print("")
print("#### Your Results ####")
print("Elapsed Time: ", total_time)
print("Correct Answers: ", i_correct)
print("Incorrect Answers: ", i_incorrect)
print("Total Answers: ", i)
print("Score: ", (i_correct/i)*100)
print("")
for entry in QuestionList:
= "Question: " + entry[0] + ", Answer: " + str(entry[1]) + ", Result: " + str(entry[2])
SummaryString print(SummaryString)
Maybe the user wants to save the results, in order to have the results available even after shutting down the computer. Therefore we can write a textfile with the results.
We define a variable fobj pointing on a file stream. The function open() opens a textfile (path to the file provided as a string). If the given flag is “w”, it writes a new textfile and saves it at the given location. With the open filestream, we can use the write()-method of the filestream in order to write into the file.
#define a variable **fobj** pointing on a file stream
= open("QuizResults.txt","w")
fobj
= "This is my result!\n"
ResultString
# write the string to the textfile
fobj.write(ResultString) fobj.close()
Note that \n is used, in order to control the formatting in multiple lines!
Let’s add this feature to our quiz:
import math
import random
import time
# Record the start time
= time.time()
start_time
#set number of questions
= 11 # only run 30 seconds
num_questions
#Set stopwatch
= 0
elapsed_time
#Define counters
= 0
i_correct = 0
i_incorrect
print(" ")
print("#### Welcome to the Quiz ####")
print("Type S to skip the question")
print("Type Q to quit the quiz")
print(" ")
= []
QuestionList for i in range(1,num_questions):
# first let python pre-calculate a math problem
= random.uniform(1, 10)
Value1 = random.uniform(1, 10)
Value2 = round(Value1,0)
Value1 = round(Value2,0)
Value2 = int(Value1)
Value1 = int(Value2)
Value2
= Value1 * Value2
Product
# let's formulate a question
= "What is the product of " + str(Value1) + " and " + str(Value2) + "? "
Question
= input(Question)
Answer
if Answer == "Q" or Answer == "q":
break
if Answer == "S" or Answer == "s":
continue
# the Answer is initially a string and has to be converted into an integer before comparison
= int(Answer)
Answer
= False
Result if Product == Answer:
= True
Result +=1
i_correctelse:
+=1
i_incorrect
# Record the elapsed time
= time.time()
current_time = int(current_time - start_time)
elapsed_time
= [Question,Answer,Result]
Summary
QuestionList.append(Summary)
= int(current_time - start_time)
total_time # print the results of the quiz after the time is over
print("")
print("#### Your Results ####")
print("Elapsed Time: ", total_time)
print("Correct Answers: ", i_correct)
print("Incorrect Answers: ", i_incorrect)
print("Total Answers: ", i)
print("Score: ", (i_correct/i)*100)
print("")
= open("QuizResults.txt","w")
fobj "#### Your Results ####\n")
fobj.write("Elapsed Time: " + str(total_time) + "\n")
fobj.write("Correct Answers: " + str(i_correct) + "\n")
fobj.write("Incorrect Answers: " + str(i_incorrect) + "\n")
fobj.write("Total Answers: " + str(i) + "\n")
fobj.write("Score: " + str((i_correct/i)*100) + "\n\n")
fobj.write(
for entry in QuestionList:
= "Question: " + entry[0] + ", Answer: " + str(entry[1]) + ", Result: " + str(entry[2])
SummaryString print(SummaryString)
+ "\n")
fobj.write(SummaryString fobj.close()
After execution a new textfile appears in the EXPLORER of VSCode. View the textfile in the Editor!
Now as we allow the user to store his results, we could evaluate how he/she improves over multiple days or weeks. Therefore we could read the information from previous runs from the file, in case the file exists.
First we import the python module os (operating system). The os-function os.path.exists() allows to check, if the provided path exists. In this case it is the relative path from the current working directory (“QuizResults.txt” is in the same folder as MyScript.py).
If the file exists, we open a filestream again. We define a variable fobj_in pointing on a file stream. The function open() opens a textfile (path to the file provided as a string). If the given flag is “r”, it reads an existing textfile from the given location.
import os
= "QuizResults.txt"
file_path
if os.path.exists(file_path):
= open(file_path, "r") fobj_in
If we have the filestream open, we can iterate through the different rows of the document, using a for-loop again. Let’s print the second row of the file (this is the row with index 1)
import os
= "QuizResults.txt"
file_path
if os.path.exists(file_path):
= open(file_path, "r")
fobj_in for index, element in enumerate(fobj_in):
if index == 1:
print(element)
print(type(element))
fobj_in.close()
Elapsed Time: 43
<class 'str'>
This is another version of a for-loop, providing both an index and the entry together. Before we have seen for-loops providing either the index (for i in range(len(List)):) or the entry (for entry in List:)
Now we want to extract the Elapsed Time information as an int in order to make it comparable to other Elapsed Time informations.
The variable element that we read here is a string. The string includes both the description and the time value itself. In order to extract the number from the string, we first split the string using the ” “ character as a splitter:
= "Elapsed Time: 43\n"
element = element.strip() # eliminiates the newline statement
element = element.split(" ")
element print(element)
print(type(element))
['Elapsed', 'Time:', '43']
<class 'list'>
Doing so, the string is split, resulting in a list containing multiple strings.
Now, we can grab the third element of the list (“43”) and convert it to int using int().
= "Elapsed Time: 43\n"
element = element.strip() # eliminiates the newline statement
element = element.split(" ")
element = int(element[2])
top_score_time print(top_score_time)
43
This allows us to read the top score time from the textfile and store it in the variable top_score_time.
import os
= "QuizResults.txt"
file_path
if os.path.exists(file_path):
= open(file_path, "r")
fobj_in for index, element in enumerate(fobj_in):
if index == 1:
= element.strip() # eliminiates the newline statement
element = element.split(" ")
element = int(element[2])
top_score_time print("Your top score time is: ", top_score_time)
fobj_in.close()
In the code below, we can compare the top score time with the elapsed time from the current questionaire. If it is shorter, we can update the top score.
if total_time < top_score_time:
= total_time
top_score_time print("Congratulations, you have a new top score time!")
The total python script for this quiz will look like this:
import math
import random
import time
import os
# Record the start time
= time.time()
start_time
#set number of questions
= 11 # only run 30 seconds
num_questions
#Set stopwatch
= 0
elapsed_time = start_time
current_time
#Define counters
= 0
i_correct = 0
i_incorrect
print(" ")
print("#### Welcome to the Quiz ####")
print("Type S to skip the question")
print("Type Q to quit the quiz")
print(" ")
= "QuizResults.txt"
file_path = 100012
top_score_time if os.path.exists(file_path):
= open(file_path, "r")
fobj_in for index, element in enumerate(fobj_in):
if index == 1:
= element.strip() # eliminiates the newline statement
element = element.split(" ")
element = int(element[2])
top_score_time print("Your top score time is: ", top_score_time)
print(" ")
fobj_in.close()
= []
QuestionList for i in range(1,num_questions):
# first let python pre-calculate a math problem
= random.uniform(1, 10)
Value1 = random.uniform(1, 10)
Value2 = round(Value1,0)
Value1 = round(Value2,0)
Value2 = int(Value1)
Value1 = int(Value2)
Value2
= Value1 * Value2
Product
# let's formulate a question
= "What is the product of " + str(Value1) + " and " + str(Value2) + "? "
Question
= input(Question)
Answer
if Answer == "Q" or Answer == "q":
break
if Answer == "S" or Answer == "s":
continue
# the Answer is initially a string and has to be converted into an integer before comparison
= int(Answer)
Answer
= False
Result if Product == Answer:
= True
Result +=1
i_correctelse:
+=1
i_incorrect
# Record the elapsed time
= time.time()
current_time = int(current_time - start_time)
elapsed_time
= [Question,Answer,Result]
Summary
QuestionList.append(Summary)
= int(current_time - start_time)
total_time
if total_time < top_score_time:
= total_time
top_score_time print("")
print("Congratulations, you have a new top score time!")
# print the results of the quiz after the time is over
print("")
print("#### Your Results ####")
print("Elapsed Time: ", total_time, " Top Score: ", top_score_time )
print("Correct Answers: ", i_correct)
print("Incorrect Answers: ", i_incorrect)
print("Total Answers: ", i)
print("Score: ", (i_correct/i)*100)
print("")
= open(file_path,"w")
fobj "#### Your Results ####\n")
fobj.write("TopScore Time: " + str(top_score_time) + "\n")
fobj.write("Correct Answers: " + str(i_correct) + "\n")
fobj.write("Incorrect Answers: " + str(i_incorrect) + "\n")
fobj.write("Total Answers: " + str(i) + "\n")
fobj.write("Score: " + str((i_correct/i)*100) + "\n\n")
fobj.write(
for entry in QuestionList:
= "Question: " + entry[0] + ", Answer: " + str(entry[1]) + ", Result: " + str(entry[2])
SummaryString print(SummaryString)
+ "\n")
fobj.write(SummaryString fobj.close()
You can see that we have already accumulated a bunch of code, which is a little bit messy, while reading becomes more and more challenging. In this case, we can help us in order to encapsulate small subtasks (e.g. reading, calculating, writing, etc… ) in a python function.
We can define a function, using the def(): statement. A function has a name that we can specify as a programmer and can receive zero, one or multiple input arguments from the user. The def() statement ends with a “:”. The work do be done within the function is then defined in an indented code block.
A function can return an output result value.
def MyFunction(Argument(optional)):
#DoSomething with Argument
return(result(optional))
You should put your function definitions to the top of your code. Let’s see, where it makes sense to encapsulate some code into a function.
If we look into our math-quiz code, the first thing that we do is printing a welcome message. We can encapsulate these lines of code into a function called print_welcome().
def print_welcome():
print(" ")
print("#### Welcome to the Quiz ####")
print("Type S to skip the question")
print("Type Q to quit the quiz")
print(" ")
We do not need neither an input argument nor a return, because we only want to print a standard welcome message!
Next we read out the top_score. We can encapsulate this task into a function called read_top_score()
def read_top_score(file_path):
= 1000
top_score_time if os.path.exists(file_path):
= open(file_path, "r")
fobj_in for index, element in enumerate(fobj_in):
if index == 1:
= element.strip() # eliminiates the newline statement
element = element.split(" ")
element = int(element[2])
top_score_time print("Your top score time is: ", top_score_time)
print(" ")
fobj_in.close()return(top_score_time)
In order to let the function know the filepath, where the top_score is stored, we need to pass the file_path as an input argument! And the function should provide the top_score_time. Thus we need to return the top_score_time.
Then we have the code block pre-calculating the path problem for the quiz. As a function it looks like this:
def getMathProblem():
= random.uniform(1, 10)
Value1 = random.uniform(1, 10)
Value2 = round(Value1,0)
Value1 = round(Value2,0)
Value2 = int(Value1)
Value1 = int(Value2)
Value2
= Value1 * Value2
Product
# let's formulate a question
= "What is the product of " + str(Value1) + " and " + str(Value2) + "? "
Question return(Product,Question)
We do not need an input argument here, because the values are generated by the random function. However, we need to return two objects: The Product and the formulated Question.
The next task is the evaluation of the given answer:
def evaluate_answer(Answer, Product, i_correct, i_incorrect):
= int(Answer)
Answer
= False
Result if Product == Answer:
= True
Result +=1
i_correctelse:
+=1
i_incorrectreturn(Result, i_correct, i_incorrect)
This function needs a bunch of input arguments, in order to do the evaluation correctly. And it also needs to return a bunch of outputs that can be processed in the next steps
Additional tasks are the printing of results and writing the score to file:
def print_results(total_time, top_score_time, QuestionList,i, i_correct, i_incorrect):
if total_time < top_score_time:
= total_time
top_score_time print("")
print("Congratulations, you have a new top score time!")
print("")
print("#### Your Results ####")
print("Elapsed Time: ", total_time, " Top Score: ", top_score_time )
print("Correct Answers: ", i_correct)
print("Incorrect Answers: ", i_incorrect)
print("Total Answers: ", i)
print("Score: ", (i_correct/i)*100)
print("")
for entry in QuestionList:
= "Question: " + entry[0] + ", Answer: " + str(entry[1]) + ", Result: " + str(entry[2])
SummaryString print(SummaryString)
def write_results(file_path, total_time, top_score_time, QuestionList,i, i_correct, i_incorrect):
= open(file_path,"w")
fobj "#### Your Results ####\n")
fobj.write("TopScore Time: " + str(top_score_time) + "\n")
fobj.write("Correct Answers: " + str(i_correct) + "\n")
fobj.write("Incorrect Answers: " + str(i_incorrect) + "\n")
fobj.write("Total Answers: " + str(i) + "\n")
fobj.write("Score: " + str((i_correct/i)*100) + "\n\n")
fobj.write(
for entry in QuestionList:
= "Question: " + entry[0] + ", Answer: " + str(entry[1]) + ", Result: " + str(entry[2])
SummaryString + "\n")
fobj.write(SummaryString fobj.close()
Make a new script called MyScript2.py If you have defined all the functions, the top of your code should look like this:
import math
import random
import time
import os
#####################################################
########### function definitions ####################
#####################################################
def print_welcome():
print(" ")
print("#### Welcome to the Quiz ####")
print("Type S to skip the question")
print("Type Q to quit the quiz")
print(" ")
def read_top_score(file_path):
= 1000
top_score_time if os.path.exists(file_path):
= open(file_path, "r")
fobj_in for index, element in enumerate(fobj_in):
if index == 1:
= element.strip() # eliminiates the newline statement
element = element.split(" ")
element = int(element[2])
top_score_time print("Your top score time is: ", top_score_time)
print(" ")
fobj_in.close()return(top_score_time)
def getMathProblem():
= random.uniform(1, 10)
Value1 = random.uniform(1, 10)
Value2 = round(Value1,0)
Value1 = round(Value2,0)
Value2 = int(Value1)
Value1 = int(Value2)
Value2
= Value1 * Value2
Product
# let's formulate a question
= "What is the product of " + str(Value1) + " and " + str(Value2) + "? "
Question return(Product,Question)
def evaluate_answer(Answer, Product, i_correct, i_incorrect):
= int(Answer)
Answer
= False
Result if Product == Answer:
= True
Result +=1
i_correctelse:
+=1
i_incorrectreturn(Result, i_correct, i_incorrect)
def print_results(total_time, top_score_time, QuestionList,i, i_correct, i_incorrect):
if total_time < top_score_time:
= total_time
top_score_time print("")
print("Congratulations, you have a new top score time!")
print("")
print("#### Your Results ####")
print("Elapsed Time: ", total_time, " Top Score: ", top_score_time )
print("Correct Answers: ", i_correct)
print("Incorrect Answers: ", i_incorrect)
print("Total Answers: ", i)
print("Score: ", (i_correct/i)*100)
print("")
for entry in QuestionList:
= "Question: " + entry[0] + ", Answer: " + str(entry[1]) + ", Result: " + str(entry[2])
SummaryString print(SummaryString)
def write_results(file_path, total_time, top_score_time, QuestionList,i, i_correct, i_incorrect):
= open(file_path,"w")
fobj "#### Your Results ####\n")
fobj.write("TopScore Time: " + str(top_score_time) + "\n")
fobj.write("Correct Answers: " + str(i_correct) + "\n")
fobj.write("Incorrect Answers: " + str(i_incorrect) + "\n")
fobj.write("Total Answers: " + str(i) + "\n")
fobj.write("Score: " + str((i_correct/i)*100) + "\n\n")
fobj.write(
for entry in QuestionList:
= "Question: " + entry[0] + ", Answer: " + str(entry[1]) + ", Result: " + str(entry[2])
SummaryString + "\n")
fobj.write(SummaryString
fobj.close()
#####################################################
########### end function definitions ################
#####################################################
If you run this script, it will do nothing! This is because a code within a function is only executed if the function is called! Functions are called as follows (compare to function definitions above):
#no argument, no return
print_welcome() = read_top_score(file_path) # one argument, one return top_score_time
Usually we can structure our code into a section where functions are defined (above) and a section where the actual execution takes place. For the latter we recommend to define a main-function using a if name == ‘main’: statement. Thereby, the scipt will look like this:
import math
import random
import time
import os
#####################################################
########### function definitions ####################
#####################################################
def print_welcome():
print(" ")
print("#### Welcome to the Quiz ####")
print("Type S to skip the question")
print("Type Q to quit the quiz")
print(" ")
def read_top_score(file_path):
= 1000
top_score_time if os.path.exists(file_path):
= open(file_path, "r")
fobj_in for index, element in enumerate(fobj_in):
if index == 1:
= element.strip() # eliminiates the newline statement
element = element.split(" ")
element = int(element[2])
top_score_time print("Your top score time is: ", top_score_time)
print(" ")
fobj_in.close()return(top_score_time)
def getMathProblem():
= random.uniform(1, 10)
Value1 = random.uniform(1, 10)
Value2 = round(Value1,0)
Value1 = round(Value2,0)
Value2 = int(Value1)
Value1 = int(Value2)
Value2
= Value1 * Value2
Product
# let's formulate a question
= "What is the product of " + str(Value1) + " and " + str(Value2) + "? "
Question return(Product,Question)
def evaluate_answer(Answer, Product, i_correct, i_incorrect):
= int(Answer)
Answer
= False
Result if Product == Answer:
= True
Result +=1
i_correctelse:
+=1
i_incorrectreturn(Result, i_correct, i_incorrect)
def print_results(total_time, top_score_time, QuestionList,i, i_correct, i_incorrect):
if total_time < top_score_time:
= total_time
top_score_time print("")
print("Congratulations, you have a new top score time!")
print("")
print("#### Your Results ####")
print("Elapsed Time: ", total_time, " Top Score: ", top_score_time )
print("Correct Answers: ", i_correct)
print("Incorrect Answers: ", i_incorrect)
print("Total Answers: ", i)
print("Score: ", (i_correct/i)*100)
print("")
for entry in QuestionList:
= "Question: " + entry[0] + ", Answer: " + str(entry[1]) + ", Result: " + str(entry[2])
SummaryString print(SummaryString)
def write_results(file_path, total_time, top_score_time, QuestionList,i, i_correct, i_incorrect):
= open(file_path,"w")
fobj "#### Your Results ####\n")
fobj.write("TopScore Time: " + str(top_score_time) + "\n")
fobj.write("Correct Answers: " + str(i_correct) + "\n")
fobj.write("Incorrect Answers: " + str(i_incorrect) + "\n")
fobj.write("Total Answers: " + str(i) + "\n")
fobj.write("Score: " + str((i_correct/i)*100) + "\n\n")
fobj.write(
for entry in QuestionList:
= "Question: " + entry[0] + ", Answer: " + str(entry[1]) + ", Result: " + str(entry[2])
SummaryString + "\n")
fobj.write(SummaryString
fobj.close()
#####################################################
########### end function definitions ################
#####################################################
#####################################################
############### the main function ###################
#####################################################
if __name__ == '__main__':
= "QuizResults.txt"
file_path
print_welcome()= read_top_score(file_path)
top_score_time #####################################################
############### end of main function ################
#####################################################
#### Welcome to the Quiz ####
Type S to skip the question
Type Q to quit the quiz
Your top score time is: 43
The main code has only four lines, but it does already the welcome print and the readout of the top score!
Now we can implement the whole math quiz using the function definitions:
import math
import random
import time
import os
#####################################################
########### function definitions ####################
#####################################################
def print_welcome():
print(" ")
print("#### Welcome to the Quiz ####")
print("Type S to skip the question")
print("Type Q to quit the quiz")
print(" ")
def read_top_score(file_path):
= 1000
top_score_time if os.path.exists(file_path):
= open(file_path, "r")
fobj_in for index, element in enumerate(fobj_in):
if index == 1:
= element.strip() # eliminiates the newline statement
element = element.split(" ")
element = int(element[2])
top_score_time print("Your top score time is: ", top_score_time)
print(" ")
fobj_in.close()return(top_score_time)
def getMathProblem():
= random.uniform(1, 10)
Value1 = random.uniform(1, 10)
Value2 = round(Value1,0)
Value1 = round(Value2,0)
Value2 = int(Value1)
Value1 = int(Value2)
Value2
= Value1 * Value2
Product
# let's formulate a question
= "What is the product of " + str(Value1) + " and " + str(Value2) + "? "
Question return(Product,Question)
def evaluate_answer(Answer, Product, i_correct, i_incorrect):
= int(Answer)
Answer
= False
Result if Product == Answer:
= True
Result +=1
i_correctelse:
+=1
i_incorrectreturn(Result, i_correct, i_incorrect)
def print_results(total_time, top_score_time, QuestionList,i, i_correct, i_incorrect):
if total_time < top_score_time:
= total_time
top_score_time print("")
print("Congratulations, you have a new top score time!")
print("")
print("#### Your Results ####")
print("Elapsed Time: ", total_time, " Top Score: ", top_score_time )
print("Correct Answers: ", i_correct)
print("Incorrect Answers: ", i_incorrect)
print("Total Answers: ", i)
print("Score: ", (i_correct/i)*100)
print("")
for entry in QuestionList:
= "Question: " + entry[0] + ", Answer: " + str(entry[1]) + ", Result: " + str(entry[2])
SummaryString print(SummaryString)
def write_results(file_path, total_time, top_score_time, QuestionList,i, i_correct, i_incorrect):
= open(file_path,"w")
fobj "#### Your Results ####\n")
fobj.write("TopScore Time: " + str(top_score_time) + "\n")
fobj.write("Correct Answers: " + str(i_correct) + "\n")
fobj.write("Incorrect Answers: " + str(i_incorrect) + "\n")
fobj.write("Total Answers: " + str(i) + "\n")
fobj.write("Score: " + str((i_correct/i)*100) + "\n\n")
fobj.write(
for entry in QuestionList:
= "Question: " + entry[0] + ", Answer: " + str(entry[1]) + ", Result: " + str(entry[2])
SummaryString + "\n")
fobj.write(SummaryString
fobj.close()
#####################################################
########### end function definitions ################
#####################################################
#####################################################
############### the main function ###################
#####################################################
if __name__ == '__main__':
#set number of questions
= 11 # only run 30 seconds
num_questions = "QuizResults.txt"
file_path
#Set stopwatch
= time.time()
start_time
#Define counters
= 0
i_correct = 0
i_incorrect
print_welcome()= read_top_score(file_path)
top_score_time
= []
QuestionList for i in range(1,num_questions):
= getMathProblem()
Product, Question = input(Question)
Answer
if Answer == "Q" or Answer == "q":
break
elif Answer == "S" or Answer == "s":
continue
= evaluate_answer(Answer, Product,i_correct, i_incorrect)
Result, i_correct, i_incorrect
= [Question,Answer,Result]
Summary
QuestionList.append(Summary)
= int(time.time() - start_time)
total_time
print_results(total_time, top_score_time, QuestionList,i, i_correct, i_incorrect)
write_results(file_path, total_time, top_score_time, QuestionList, i, i_correct, i_incorrect)
#####################################################
############### end of main function ################
#####################################################
Note that the main code has a limited number of lines now and the readability has improved.
In order to get our quiz-code even more readable and short, we can “outsource” our function definitions to a separate file. If we have the functions defined in a separate file, we can import this file as a module and use the functions in any script we like. This also allows to use the same functions without re-implemeting them, avoiding code duplications.
As a programmer, we do not have to think of the solution of a specific problem multiple times and only have to call the function without knowing the exact algorithm behind.
Create a new python script called lis_cmd.py and copy all the module imports and function definitions into it:
import math
import random
import time
import os
#####################################################
########### function definitions ####################
#####################################################
def print_welcome():
print(" ")
print("#### Welcome to the Quiz ####")
print("Type S to skip the question")
print("Type Q to quit the quiz")
print(" ")
def read_top_score(file_path):
= 1000
top_score_time if os.path.exists(file_path):
= open(file_path, "r")
fobj_in for index, element in enumerate(fobj_in):
if index == 1:
= element.strip() # eliminiates the newline statement
element = element.split(" ")
element = int(element[2])
top_score_time print("Your top score time is: ", top_score_time)
print(" ")
fobj_in.close()return(top_score_time)
def getMathProblem():
= random.uniform(1, 10)
Value1 = random.uniform(1, 10)
Value2 = round(Value1,0)
Value1 = round(Value2,0)
Value2 = int(Value1)
Value1 = int(Value2)
Value2
= Value1 * Value2
Product
# let's formulate a question
= "What is the product of " + str(Value1) + " and " + str(Value2) + "? "
Question return(Product,Question)
def evaluate_answer(Answer, Product, i_correct, i_incorrect):
= int(Answer)
Answer
= False
Result if Product == Answer:
= True
Result +=1
i_correctelse:
+=1
i_incorrectreturn(Result, i_correct, i_incorrect)
def print_results(total_time, top_score_time, QuestionList,i, i_correct, i_incorrect):
if total_time < top_score_time:
= total_time
top_score_time print("")
print("Congratulations, you have a new top score time!")
print("")
print("#### Your Results ####")
print("Elapsed Time: ", total_time, " Top Score: ", top_score_time )
print("Correct Answers: ", i_correct)
print("Incorrect Answers: ", i_incorrect)
print("Total Answers: ", i)
print("Score: ", (i_correct/i)*100)
print("")
for entry in QuestionList:
= "Question: " + entry[0] + ", Answer: " + str(entry[1]) + ", Result: " + str(entry[2])
SummaryString print(SummaryString)
def write_results(file_path, total_time, top_score_time, QuestionList,i, i_correct, i_incorrect):
= open(file_path,"w")
fobj "#### Your Results ####\n")
fobj.write("TopScore Time: " + str(top_score_time) + "\n")
fobj.write("Correct Answers: " + str(i_correct) + "\n")
fobj.write("Incorrect Answers: " + str(i_incorrect) + "\n")
fobj.write("Total Answers: " + str(i) + "\n")
fobj.write("Score: " + str((i_correct/i)*100) + "\n\n")
fobj.write(
for entry in QuestionList:
= "Question: " + entry[0] + ", Answer: " + str(entry[1]) + ", Result: " + str(entry[2])
SummaryString + "\n")
fobj.write(SummaryString
fobj.close()
#####################################################
########### end function definitions ################
#####################################################
Save the script!
Note that this script does nothing when executed, because it only contains the function definitions.
Delete all the function definitions from main script. Now your script should only have these lines:
import math
import random
import time
import os
if __name__ == '__main__':
#set number of questions
= 11 # only run 30 seconds
num_questions = "QuizResults.txt"
file_path
#Set stopwatch
= time.time()
start_time
#Define counters
= 0
i_correct = 0
i_incorrect
print_welcome()= read_top_score(file_path)
top_score_time
= []
QuestionList for i in range(1,num_questions):
= getMathProblem()
Product, Question = input(Question)
Answer
if Answer == "Q" or Answer == "q":
break
elif Answer == "S" or Answer == "s":
continue
= evaluate_answer(Answer, Product,i_correct, i_incorrect)
Result, i_correct, i_incorrect
= [Question,Answer,Result]
Summary
QuestionList.append(Summary)
= int(time.time() - start_time)
total_time
print_results(total_time, top_score_time, QuestionList,i, i_correct, i_incorrect) write_results(file_path, total_time, top_score_time, QuestionList, i, i_correct, i_incorrect)
If you try to run the main script now, you will get an error message. This is because the functions you want to call here are not defined. To be more specific, python still doesn’t now where to find the function definitions.
In order to help python finding your function definitions in the command script. You have to import lis_cmd and use the namespace lis_cmd, in order to call the function of interest (lis_cmd.print_welcome())
import lis_cmd
lis_cmd.print_welcome()
In the final main script it will look like this:
import math
import random
import time
import os
import lis_cmd
if __name__ == '__main__':
#Set stopwatch
= time.time()
start_time
#Define counters
= 0
i_correct = 0
i_incorrect
lis_cmd.print_welcome()= lis_cmd.read_top_score(file_path)
top_score_time
= []
QuestionList for i in range(1,num_questions):
= lis_cmd.getMathProblem()
Product, Question = input(Question)
Answer
if Answer == "Q" or Answer == "q":
break
elif Answer == "S" or Answer == "s":
continue
= lis_cmd.evaluate_answer(Answer, Product,i_correct, i_incorrect)
Result, i_correct, i_incorrect
= [Question,Answer,Result]
Summary
QuestionList.append(Summary)
= int(time.time() - start_time)
total_time
lis_cmd.print_results(total_time, top_score_time, QuestionList,i, i_correct, i_incorrect) lis_cmd.write_results(file_path, total_time, top_score_time, QuestionList,i, i_correct, i_incorrect)
In our math quiz we have two user defined parameters: the number_of_questions and the file_path for the quiz results and the top score. While reading the code, it is not eye-catching that these two parameters can be tweaked in order to change the behaviour of the script. Therefore it is recommended to also outsource these parameters into a configuration files
Create a new python script called project_config.py and copy the parameter definitions into it:
= 11
num_questions = "QuizResults.txt" file_path
Save the script!
Delete the two lines in the main script.
= 11
num_questions = "QuizResults.txt" file_path
Import project_config in your main script and use the namespace when using the parameters (project_config.file_name, project_config.num_questions)
import project_config
project_config.file_path
The final main script will look like this:
import math
import random
import time
import os
import lis_cmd
import project_config
if __name__ == '__main__':
#Set stopwatch
= time.time()
start_time
#Define counters
= 0
i_correct = 0
i_incorrect
lis_cmd.print_welcome()= lis_cmd.read_top_score(project_config.file_path)
top_score_time
= []
QuestionList for i in range(1,project_config.num_questions):
= lis_cmd.getMathProblem()
Product, Question = input(Question)
Answer
if Answer == "Q" or Answer == "q":
break
elif Answer == "S" or Answer == "s":
continue
= lis_cmd.evaluate_answer(Answer, Product,i_correct, i_incorrect)
Result, i_correct, i_incorrect
= [Question,Answer,Result]
Summary
QuestionList.append(Summary)
= int(time.time() - start_time)
total_time
lis_cmd.print_results(total_time, top_score_time, QuestionList,i, i_correct, i_incorrect) lis_cmd.write_results(project_config.file_path, total_time, top_score_time, QuestionList,i, i_correct, i_incorrect)
Now, if you want to change the file_name or the num_questions, you only need to look into the project_config.py and make changes there. In this case you don’t need to make any changes in the main script.
In this tutorial you have learned a lot of python basics and can solve programming problems now. In the next tutorials, we will learn how to exploit this for automating large lidar processing projects using LIS Pro 3D and Python.