Termbank
  1. A
    1. Absolute Path
    2. Ajonaikainen
      concepts
    3. Alustaminen
      variables values
    4. Argumentti
      values functions
    5. Arvo
      values
    6. Assignment
      variables values
    7. Assignment Operator
      variables values operators
    8. Attribute
      objects
    9. Attribuutti
      Attribute
    10. Avainsana
      names
    11. Aliohjelma
      Function
  2. B
    1. Boolean
      control flow
    2. Boolean Operator
      control flow operators
    3. Boolen operaattori
      Boolean Operator
    4. Branch
      try structures conditional structures
    5. Bug
      problem solving
    6. Bugi
      Bug
    7. Builtin Function
      functions
    8. Block
      Code Block
    9. break
      loops keywords
  3. C
    1. Callback
      functions
    2. Carriage Return
      escaping strings files windows
    3. Code Block
      control flow functions
    4. Code File
      concepts
    5. Command Line Argument
      terminal
    6. Comparison Operator
      control flow operators
    7. Comparison Value
    8. Condition
      control flow
    9. Conditional Statement
      control flow
    10. Conditional Structure
      conditional structures control flow
    11. Constant
      variables values
    12. Control Structure
      try structures loops conditional structures
    13. Call
      Function Call
    14. Ctrl + C
      Näppäimistökeskeytys
    15. Code
      Source Code
    16. Callback
      Takaisinkutsu
    17. Command Prompt
      Terminal
    18. continue
      loops keywords
  4. D
    1. Data
    2. Data Format
      strings files
    3. Data Structure
      dictionaries concepts lists
    4. Debugging
    5. Default Value
      values functions parameters
    6. Dictionary
      data structures
    7. Docstring
      documentation
  5. E
    1. Epätosi
      values
    2. Error Message
      problem solving
    3. Escape
      strings
    4. Evaluointi
      expressions values
    5. Event
      concepts
    6. Exception
      try structures problem solving
    7. Exception class
      exceptions control flow
    8. Execution
      expressions concepts
    9. Element
      Item
    10. enumerate
      lists loops
  6. F
    1. False
      Epätosi
    2. File Extension
      files
    3. File Handle
      objects files
    4. Filename
      strings files
    5. Float
      values types
    6. Format
      strings printing
    7. Formatting
      Format
    8. Function
      functions
    9. Function Call
      functions statements
    10. Function Definition
    11. f string
      strings
    12. for
  7. G
    1. Generator
      objects loops
    2. Globaali muuttuja
      variables values
    3. Global Scope
  8. H
    1. Handle
      File Handle
    2. Handler
      functions concepts
    3. Hyppy
      control flow
    4. Hardkoodaus
      Kovakoodaus
  9. I
    1. if statement
      Conditional Statement
    2. if structure
      Conditional Structure
    3. Identifier
      variables functions
    4. Indentation
      concepts
    5. Index
      values lists
    6. Index Subscription
      values lists
    7. Infinite Loop
      loops
    8. Input
      strings concepts
    9. Interface
      modules functions concepts
    10. Item
      values lists
    11. Iteration
      loops
    12. import
      modules
  10. K
    1. Key
      dictionaries values
    2. Keyword Argument
      functions
    3. Kirjasto
      modules
    4. Kommentti
      debugging documentation
    5. Kovakoodaus
      values
    6. Käyttöliittymäelementti
    7. KeyboardInterrupt
      Näppäimistökeskeytys
  11. L
    1. Lause
      concepts
    2. Lauseke
      concepts
    3. List
    4. Literal
      values
    5. Local Variable
    6. Loop
      control flow
    7. Loop Variable
      variables loops
  12. M
    1. Main Program
      concepts
    2. Merkki
    3. Merkkijono
      values types
    4. Method
      functions objects
    5. Member Function
      Method
    6. Method Call
      expressions objects
    7. Module
    8. Mutable
      values concepts lists
    9. Muuntumaton
      values strings concepts
    10. Määrittely
      concepts
  13. N
    1. Name Conflict
    2. Namespace
      modules functions concepts
    3. Newline
      strings files
    4. Nimeämätön vakio
      values constants
    5. Näppäimistökeskeytys
      exceptions
  14. O
    1. Objekti
      concepts
    2. Olio
      Objekti
    3. Ohjelmointityyli
    4. Ominaisuus
      objects
    5. Opening Mode
      files
    6. Operand
    7. Operation
      expressions
    8. Operator
    9. Optional Argument
      values functions parameters
  15. P
    1. Parameter
      functions
    2. Parametrization
    3. Path
    4. Placeholder
      strings printing
    5. Poikkeusten käsittely
      control flow exceptions
    6. Precedence
      expressions concepts
    7. Presedenssi
      Precedence
    8. Precedence
    9. Printing
      strings concepts
    10. Programming Problem
      problem solving
    11. Python Console
      tools
    12. Python Interpreter
      tools
  16. R
    1. Running
      Execution
    2. Recursion
      functions concepts
    3. Referring
      variables values objects
    4. Relative Path
    5. Return
      values functions
    6. Return Value
  17. S
    1. Silmukka
      Loop
    2. Suoritusjärjestys
      Precedence
    3. Sapluuna
      strings concepts
    4. Scope
      concepts blocks
    5. Separator
      strings files lists input
    6. Sequence
      data structures concepts loops
    7. Slicing
      lists
    8. Solution Model
      problem solving
    9. Source Code
      concepts
    10. State
      concepts
    11. Stub
      problem solving functions
    12. Syntax
      concepts
    13. Syntax Error
      exceptions
    14. Shell
      Terminal
    15. Stacktrace
      Traceback
  18. T
    1. Taikaluku
      Nimeämätön vakio
    2. try-rakenne
      Poikkeusten käsittely
    3. Takaisinkutsu
      functions
    4. Terminal
      tools
    5. Testaaminen
      problem solving concepts
    6. Text File
      files
    7. Tosi
      values
    8. True
      Tosi
    9. Traceback
      problem solving
    10. Tuple
      data structures lists
    11. Type Conversion
      values functions types
    12. Tyylisääntö
    13. Tyyppi
      values concepts
  19. U
    1. User Interface
      concepts
  20. V
    1. Variable
      values concepts
  21. W
    1. while
      loops
    2. with
      files
Completed: / exercises

3. Material: Loopy Lists

Everything is Recurrence

The evolution of programming skills is quite rapid in this course. In the first material our programs were straight as arrows. Last time we made them branch based on user input. So far our programs have only processed data as individual values of predetermined quantity. For example, we've used two variables, number_1 and number_2 to refer to exactly two numbers.
However, in real life, it's very easy to come up with scenarios where the quantity of data is not predetermined. Even if we had a predetermined quantity of data it's not much help for any significant number of values: if we have a thousand numbers, we would need a thousand code lines to handle them with what we currently know.
This material is very ambitious as we are tackling both lists and loop structures at the same time. These will be the last important pieces of the programming puzzle. Having said that, the ambition will be cut a bit short cause we're leaving a few details for the next material. Nevertheless, the tools introduced here allow you to solve almost all kinds of programming problems - in theory. In practice, real world programming involves a lot of topics beyond the basics covered in this and previous materials. Still, everything is built on the same basic principles. What comes after the basics is more often about using tools to avoid reinventing the wheel every time.
Our biggest limitation after this material will be the inability to access files on the computer's hard drive. This puts things like processing measurement data beyond us - for now. We also will be lacking the ability to modify lists. For instance, placing mines in a field stored as lists won't be quite possible yet.

Another Prompt Lesson: Questions Are Forever

One of the results from the last material was a program that converted US customary units to SI units. The program had one recurring prompt: Input value to convert: . We left input checking on our todo list in the name of simplicity. However, if it was a real program it should have obviously handled those situations without crashing. Another obvious flaw with the program was having to restart it after each conversion.
Learning goals: In this section you'll learn to implement one type of a loop and use that to create programs capable of repeating some code indefinitely. We'll go through the philopsophy of this common construct and, naturally, show you how to implement it in Python. After this section you'll know how to make stubborn input functions that prompt for a value until the user provides a valid one.

Forced Repetition with Option to Break Out

Image source 1
Loop structures
are relatives of
conditional structures
, and they both belong to a larger family:
control structures
, or control flow statements. The has pretty clear implications about their nature: they are structures that control the program's execution in one way or another. Whereas conditional structures create branching paths, loop structures create repetition. Hence the name loop.
Two varieties of loops exist in Python (and most other languages). The one we'll introduce first is a quite close relative to conditional structures. Whereas conditional structures use a condition to determine whether code underneath them should be executed or not, the corresponding loop structure uses its condition to determine how many times the code underneath is repeated - the code is repeated as long as the condition is true. The truthfulness is re-evaluated after each iteration. As code:
word = ""
while len(word) < 8:
    word = input("Write a word with at least 8 letters: ")
print("You wrote the word", word)
This condition uses the len
function
that returns its
argument's
length (e.g.
string's
length). This code would prompt the user for
input
until they give one that has at least 8 characters. Note that the
condition
is reverse of the end condition: as long as the word string is shorter than 8, the input prompt gets repeated.
In most languages, while is the loop to use in these kinds of scenarios where the loop's end condition depends on something that happens inside the loop itself. In this particular example, at the time of implementing the code, we have no way of knowing how many times a user will input a word with less than 8 characters. We simply have to define the loop to end exactly on the iteration when the user gives a desired string. In short, a
while loop
is suitable for situations where it's impossible to predict the amount of iterations before executing the loop.

Emergency Code

A very typical use scenario for the while loop is one where the user is prompted for an input until they don't want to do so anymore. In this example the user is inputting morse code one character at a time until a code input ends with the ! character. After this the program shoots the code into the ether - as we know, sending morse code with modern computers is a very efficient way of communication...
Learning goals: Declaring a
while loop
with a condition depending on user's input. A bit of review about writing
conditions
.

Introduction:
The loop declaration must be written so that it fits into this template:
letter = ""
# your loop is declared here
    letter = input("Mors mors! Exclamation (!) ends: ")

Answer Specification:
The answer we're looking for is a while loop declaration that fits into the template. The loop must continue as long as the last character in the letter variable does not end with the termination character !. The answer should be exactly one line.
Your answer should contain the loop's definition line.
Warning: You have not logged in. You cannot answer.
Back to the task at hand. We want to have a program that prompts the user for a number until they actually give a valid one. The word in this sentence that hints at
loops
- and while loop in particular - is until. There's a clear need in the program to repeat certain line(s) of code, and at implementation time we cannot say how many iterations are going to be needed. A while loop is ideal for the job, but we do have a roadbump. So far we've been checking validity of numbers with a try structure. We haven't done that with
conditions
for a very good reason: a condition that would accept all
floats
Python considers valid would be extremely complex.

Jailbreak

In order to solve the problem at hand, we should cover all the different ways to end a
loop
. So far we're only aware of one: the
while
loop ends when its
condition
is no longer true. But that's not the only way. The loop also ends if there's an unhandled
exception
during it:
In [1]: while True:
   ...:     number = float(input("Input number: "))
   ...:
Input number: 15
Input number: donkey
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-1-bd285c9d1f25> in <module>()
      1 while True:
----> 2     number = float(input("Input number: "))
      3 
The condition of this loop is literal True so it clearly cannot end via its condition becoming false. In this example, there's an exception: the user is trying to input something that cannot be interpreted as a number. This causes the loop to end. If, instead, there was a try structure inside the loop, it would not be possible to exit the loop with an invalid input:
In [1]: while True:
   ...:     try:
   ...:         number = float(input("Input number: "))
   ...:     except ValueError:
   ...:         print("This isn't a number")
   ...:
Input number: 15
Input number: aasi
This isn't a number
Input number: 40
Input number:
Image source 2

A Key to Freedom

How to get out of the loop in this example? Text input no longer makes the program crash so what can be done? There are two different exceptions that the user can cause by pressing some keys to escape from the loop. We already know the more important one of these, but let's review it to make sure!
Learning goals: Recall how an
input
prompt can be interrupted with an
exception
.

Introduction:
If needed, you can always check the "Computational Violence" task from the 2. material.

Answer Specification:
We're looking for an exception's name.
Name the exception here
Warning: You have not logged in. You cannot answer.
There are cleaner ways to end a
loop
than what went down in the task above. If the loop is inside a
function
it will end when the function's
return
statement is encountered inside the loop. Similarly, encountering a break statement inside the loop immediately ends it. This is a new trick, but not particularly complicted. When the
break
statement is encountered, program execution immediately slips out of the current loop, and resumes from the first line that's after the loop. Let's modify the above example further by adding a break statement in the else
branch
:
In [1]: while True:
   ...:     try:
   ...:         number = float(input("Input number: "))
   ...:     except ValueError:
   ...:         print("This isn't a number")
   ...:     else:
   ...:         break
   ...:
Input number: aasi
This isn't a number
Input number: 40
The key to understanding what happens above is remembering how the else branch works: it's entered when the try branch is executed entirely without errors. Let's put this new tech into our existing code. Shown here is the length function.
def length():
    print("Select unit of length from the options below using the abreviations")
    print("Inch (in or \")")
    print("Foot (ft or ')")
    print("Yard (yd)")
    print("Mile (mi)")
    unit = input("Input source unit: ")
    while True:    
        try:
            value = float(input("Input value to convert: "))
        except ValueError:
            print("Value must be a plain number")
        else:
            break
    try:
        conversion = LENGTH_FACTORS[unit]
    except KeyError:
        print("The selected unit is not supported.")
    else:
        print(f"{value:.2f} {unit} is {value * conversion:.2f} m")
This works but is starting to look very unpleasant. Even more so when considering we'd need to put the same snippet into three other functions. Not to mention how horrible the code would look if we had to make more than one of these prompts. Luckily we can make tidy things up a lot by moving this loop monstrosity to its own
function
. Let's call it prompt_value:
def prompt_value()
    while True:
        try:
            value = float(input("Input value to convert: "))
        except ValueError:
            print("Value must be a plain number")
        else:
            break
    return value
Of course in order to make this work as a function, we had to add
return
to the end, so that the value can actually be made available where the function is
called
. We also very recently learned that it's possible to exit loops with a return statement. Using this knowledge we can just drop the return in place of the break:
def prompt_value()
    while True:
        try:
            value = float(input("Input value to convert: "))
        except ValueError:
            print("Value must be a plain number")
        else:
            return value
Now, if we use this function in the code we had before, the result looks just as neat as it looked before we added input checking. One could claim it's even better because the function name is more descriptive of what's happening.
def length():
    print("Select unit of length from the options below using the abreviations")
    print("Inch (in or \")")
    print("Foot (ft or ')")
    print("Yard (yd)")
    print("Mile (mi)")
    unit = input("Input source unit: ")
    value = prompt_value()
    try:
        conversion = LENGTH_FACTORS[unit]
    except KeyError:
        print("The selected unit is not supported.")
    else:
        print(f"{value:.2f} {unit} is {value * conversion:.2f} m")
The same change can be applied to every function, and everything works almost exactly as it did before. The only minor difference is having a different prompt in the temperature conversion since it used to say "Input temperature" but now it's just "Input value to convert" like all the others.

Passwordfishing

Passwords are needed everywhere these days. Most places also place restrictions regarding how strong passwords must be so that they are more difficult to break using brute force techniques (i.e. using a program to try all possible combinations rapidly). In a very simple scenario, some kind of minimum length is required. Let's implement our version of this very simple check. We'll sate ourselves with 8 characters. However, in present day 32 characters would not be an exaggeration. Password length is also more meaningful - requiring numbers and special characters is almost superstition in comparison.
Learning goals: Implementing a simple
input
function using
conditional statement
and
break
.

Function Specification: prompt_password
  • Returns
    :
    • the password given by the user (string)
Write a
function
that prompts the user for
string
until they give a string that is at least 8 characters long. The prompt and feedback strings can be copied from the examples below. The function is easier to implement by using a while True loop and a separate conditional statement than by using a
while loop
with an actual
condition
. The brand new break statement will be helpful.

Function Testing:
You can call your function in the main program in order to test it.
print(prompt_password())
When testing your code remember to check the edge cases: 8 characters should be accepted and 7 rejected!

Use Example:
Write password: banana
The password must be at least 8 characters long
Write password: bananaboat
Warning: You have not logged in. You cannot answer.

Looped for Life

Another feature that would vastly enhance the user experience of our program: not exiting after each conversion. The user has went through some trouble to even get to the point where they can do a conversion. It'd be polite to allow them to do multiple conversions without repeating each step every time. We don't even need any new tricks to achieve this. Let's start with the main program that we left in this state:
print("This program converts US customary units to SI units")
print("Available features:")
print("(L)ength")
print("(M)ass")
print("(V)olume")
print("(T)emperature")
print()
choice = input("Make your choice: ").strip().lower()
if choice == "l" or choice == "length":
    length()
elif choice == "m" or choice == "mass":
    mass()
elif choice == "v" or choice == "volume":
    volume()
elif choice == "t" or choice == "temperature":
    temperature()
else:
    print("The selected feature is not available")
Making the program repeat itself is quite easily achieved with a simple
while
loop:
print("This program converts US customary units to SI units")
print("Available features:")
print("(L)ength")
print("(M)ass")
print("(V)olume")
print("(T)emperature")
print()
while True:
    choice = input("Make your choice: ").strip().lower()
    if choice == "l" or choice == "length":
        length()
    elif choice == "m" or choice == "mass":
        mass()
    elif choice == "v" or choice == "volume":
        volume()
    elif choice == "t" or choice == "temperature":
        temperature()
    else:
        print("The selected feature is not available")
Unfortunately it's now impossible for the user to exit the program without using software violence (i.e. keyboard interrupt). Previously the program exited by itself, but now exiting has to be programmed into it. We need to add a menu option to quit the program. In line with the previous options we choose a single letter shortcut for it: q for quit. We've already learned that
break
can be used to exit a loop. In this case it will also exit the program simply because there's nothing left to execute after the
loop
. Let us add another
branch
to the
conditional structure
for quit, and add it to the instructions:
print("This program converts US customary units to SI units")
print("Available features:")
print("(L)ength")
print("(M)ass")
print("(V)olume")
print("(T)emperature")
print("(Q)uit")
print()
while True:
    choice = input("Make your choice: ").strip().lower()
    if choice == "l" or choice == "length":
        length()
    elif choice == "m" or choice == "mass":
        mass()
    elif choice == "v" or choice == "volume":
        volume()
    elif choice == "t" or choice == "temperature":
        temperature()
    elif choice == "q" or choice == "quit":
        break
    else:
        print("The selected feature is not available")
Now the user isn't kicked out of the program after a conversion:
This program converts US customary units to SI units
Available features:
(L)ength
(M)ass
(V)olume
(T)emperature
(Q)uit

Make your choice: l
Select unit of length from the options below using the abreviations
Inch (in or ")
Foot (ft or ')
Yard (yd)
Mile (mi)
Input source unit: yd
Input value to convert: 12
12.000 yd is 10.973 m
Make your choice: 
Returning the user all the way to the main menu is also a bit rude in case they wanted to do another length conversion. A similar
loop
should be included in every
function
. We also need to decide which input to use for exiting the function. We're going to choose the unit choice because it's prompted first, and doesn't require changes for the value prompt function. Instead of prompting the user to give a specific letter to return, we're going to use empty input to indicate it. There's no
conditional structure
to add this option to, so we'll just add one:
def length():
    print("Select unit of length from the options below using the abreviations")
    print("Inch (in or \")")
    print("Foot (ft or ')")
    print("Yard (yd)")
    print("Mile (mi)")
    while True:
        unit = input("Input source unit: ")
        if not unit:
            break
        value = prompt_value()
        try:
            conversion = LENGTH_FACTORS[unit]
        except KeyError:
            print("The selected unit is not supported.")
        else:
            print(f"{value:.2f} {unit} is {value * conversion:.2f} m")
Note how the break is placed inside a simple if not unit: conditional statement above the value prompt. With this simple combination of two lines the loop ends immediately when the user gives an empty
input
. It works as expected:
This program converts US customary units to SI units
Available features:
(L)ength
(M)ass
(V)olume
(T)emperature
(Q)uit

Make your choice: l
Select unit of length from the options below using the abreviations
Inch (in or ")
Foot (ft or ')
Yard (yd)
Mile (mi)
Input source unit: mi
Input value to convert: 10
10.000 mi is 16093.440 m
Input source unit: 
Make your choice: q
If it wasn't proven before, this example clearly shows how both
break
and
return
exit a
loop
immediately. Even the ongoing
iteration
is interrupted midway. Therefore the value is never prompted. Shown below is an animation from another program where empty
input
is used for breaking a loop.

Listful Transition

Next we're using the ongoing example to transition to the next topic - very smoothly, promise. (Way) earlier we had an idea about inputting the value and the unit at the same time. It could work like this:
Enter value and unit to convert: 12 yd
12.000 yd is 10.973 m
Learning goals: This section teaches you what exactly is a list and how it's related to types we've studied previously. You'll also learn how to create lists by splitting strings and how to handle potential issues in the process.

Splitting Hairs

So the big question is: how exactly can we take out two different values from a single
string
? As usual, the exact solution depends on the context, but the most common way is to the string split
method
. It's a method that splits the string using an
argument
as the separator. The separator can be a string with any number of characters, and it will be left out from the results. For instance, a decimal number could be separated to its integer and decimal part by splitting at the period:
In [1]: "12.54".split(".")
Out[1]: ['12', '54']
Split also supports an
optional argument
for limiting how many splits will be done (at most). This feature is particularly useful for separating
file extensions
from the rest of the
filename
. Periods are perfectly valid characters in filenames, e.g. music files can contain them (e.g. P.H.O.B.O.S. - 03 - Wisdoom.ogg or installation packages that often have their versin number in the name (e.g. Python installer: python-3.8.1.exe). In these particular scenarios we would use the rsplit method. It's the same as split except it starts splitting from the end.
In [1]: filename = "donkey_bridge_2.5.7.zip"
In [2]: filename.rsplit(".", 1)
Out[2]: ["donkey_bridge_2.5.7", "zip"]
This example only does one split. Because the
method
is rsplit, splitting starts from the end. This allows the code to separate the file extension from rest of the name. The value
returned
by this method, enclosed in square braces, is known as a
list
. We've actually seen them before, as return values of the dir function:
In [1]: dir("")
Out[1]: 
['__add__',
 '__class__',
 '__contains__',
 '__delattr__',
 '__dir__',
 '__doc__',
 '__eq__',
 '__format__',
 '__ge__',
 '__getattribute__',
 '__getitem__',
 '__getnewargs__',
 '__gt__',
 '__hash__',
 '__init__',
 '__iter__',
 '__le__',
 '__len__',
 '__lt__',
 '__mod__',
 '__mul__',
 '__ne__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__rmod__',
 '__rmul__',
 '__setattr__',
 '__sizeof__',
 '__str__',
 '__subclasshook__',
 'capitalize',
 'casefold',
 'center',
 'count',
 'encode',
 'endswith',
 'expandtabs',
 'find',
 'format',
 'format_map',
 'index',
 'isalnum',
 'isalpha',
 'isdecimal',
 'isdigit',
 'isidentifier',
 'islower',
 'isnumeric',
 'isprintable',
 'isspace',
 'istitle',
 'isupper',
 'join',
 'ljust',
 'lower',
 'lstrip',
 'maketrans',
 'partition',
 'replace',
 'rfind',
 'rindex',
 'rjust',
 'rpartition',
 'rsplit',
 'rstrip',
 'split',
 'splitlines',
 'startswith',
 'strip',
 'swapcase',
 'title',
 'translate',
 'upper',
 'zfill']
Just like quotation characters denote a
string
or curly braces a
dictionary
, square braces denote a
list
. Out of all types we know so far, these two are also the closest relatives to lists - both in their own ways. Like strings, lists are also
sequences
as in sequence of individual values. Like dictionaries, lists are
mutable
data structures
. We had the following goal in mind:
Enter value and unit to convert: 12 yd
12.000 yd is 10.973 m
}}}4

With what we just learned, we should be able to make a list of the user's [!term=Input!]input[!term!] by using the split [!term=Method!]method[!term!], using space as the separator:

{{{
value_unit = input("Enter value and unit to convert: ").split(" ")

Lists 101

Image source 3
A very short crash course on lists can be given with a four word description: ordered collection of values. Each of the three significant words tells something crucial about lists:
In comparison: a dictionary is (mostly) unordered colelction of values - the selling point of lists is the ability to control the ordering of contents. In current version of Python dictionaries also do have a determined order, but it cannot be changed. From the perspective of syntax, a list is denoted with square braces, containing values separated by commas. And as we've learned with functions and function calls, each comma should be followed by a single space. Lists can contain numbers:
In [1]: results = [12.54, 5.12, 38.14, 9.04]
or
strings
:
In [2]: members = ["Haruna", "Tomomi", "Mami", "Rina"]
or even
functions
, as a reminder that even functions are actually
objects
:
In [3]: functions = [max, abs, min, round]
or you can stuff
dictionaries
into a list, and list definition can be split into multiple lines too:
In [4]: measurements = [
   ...:     {"value": 4.64, "unit": "in"},
   ...:     {"value": 13.54, "unit": "yd"}
   ...: ]
and, like we promised,
lists
can be made of lists:
In [5]: [results, members, functions, measurements]                                                                  
Out[5]: 
[[12.54, 5.12, 38.14, 9.04],
 ['Haruna', 'Tomomi', 'Mami', 'Rina'],
 [<function max>,
  <function abs>,
  <function min>,
  <function round>],
 [{'value': 4.64, 'unit': 'in'}, {'value': 13.54, 'unit': 'yd'}]]
The last example shows what lists look like inside a list. Unlike strings that use the same character at the beginning and end, lists use different characters (left and right brace). This makes it possible to start another list definition while inside a previous list definition with a second left brace. Of course it then becomes the programmer's responsibility to also close all the lists they have started. Otherwise the result is the same syntax error as when forgetting to close all braces on a line that contains nested function calls.

This Week's Day Exercise

One use for lists giving names to numbers. For instance when counting weekdays the results are typically numbers (e.g. 3rd day of the week), and the corresponding weekday name must then be found from somewhere. If the names are in a list, we can just take the third item and then receive the corresponding weekday (Wednesday).
Learning goals: Creating a
list
that contains items.

Answer Specification:
Type a line of code that defines a list containing all weekdays as
strings
from Monday to Sunday (in this order), all lowercase. The list must be
assigned
to the weekdays
variable
Type the code line into the box
Warning: You have not logged in. You cannot answer.

A Listful of Results

Lists can contain all kinds of things. Variables as list items are daily bread, but operation and function call results can also be put into them. In all cases the list will contain the value that is the result of the operation or call.
Learning goals: This task shows you that
list
items
can be defined as
operations
,
function
and
method calls
, in addition to
literal value
.

Introduction:
Write the following line into the
Python console
without changing it.
In [1]: [1 + 6, 6 - 4, max(4, 7), "donkey".upper()]

Answer Specification:
Copy the resulting list from the console.
Copy your result into the answer box.
Warning: You have not logged in. You cannot answer.

Listful Indexing

One common error in thinking goes as follows: if there are variables in the vein of number_1, number_2 etc. could variables like this be created dynamically so that the code would generate variables all the way to number_n? The short answer is: NO (long answer: sort of yes, but it involves overly clever tricks that will mess up your code). A similar result is achievable however, the question is just slightly wrong. The correct question would be: how to maintain a non-predetermined number of values. The answer to this question is:
list
. A list can store N
values
, and they are kept in an order. Compare this:
In [1]: number_1 = 13
In [2]: number_2 = 6
In [3]: number_3 = 24
to this:
In [4]: numbers = [13, 6, 24]
The latter solution is markedly better because it doesn't tie the number that refers to each value (13, 6 or 24) to a variable name. But how would we access each individual number in the list solution?
Items
in a list are in a determined order. This order is based on each item's distance from the beginning of the list so that the first item's (value 13) distance is 0. In order to refer to the first item of the list, we would use the number 0. The numbers that indicate this distance have a name:
index
. It works very similarly to
dictionary
keys
.
Referring with index is done with the following syntax:
In [5]: numbers[0]
Out[5]: 13
In [6]: numbers[1]
Out[6]: 6
In [7]: numbers[2]
Out[7]: 24
The square braces at the end of a
list
have the same meaning as key lookup:
subscription
via index. The critical difference is that while dictionary keys can be arbitrary
immutable
values, list indices are always integers going from 0 to list length - 1 (i.e. 0,...,N-1). This isn't actually exclusive to lists - it works for other sequences too, like
strings
. For instance, if you want to check the first letter of a word:
In [1]: word = "donkeyswings"
Out[1]: word[0]
'd'

Catalog Indexing

Learning goals: Getting a single
item
from a
list
with
index subscription
.

Introduction:
As an example scenario we have a
data structure
that contains information about a song and would be useful e.g. in a music player program. In this case we have: artist name, album title, song title and length. An example song can be assigned to a
variable
in the
Python console
as follows:
In [1]: song = ["Dirge", "Wings of Lead Over Dormant Seas", "Wings of Lead Over Dormant Seas", "60:00"]

Answer Specification:
The goal is to get the song's length into a separate variable named length. Write a line that uses index subscription to retrieve the length from the list and
assigns
it to a variable. Naturally your answer should use the song variable as the list it subscribes from.
Write your code line here,
Warning: You have not logged in. You cannot answer.
Whether we're talking about
lists
or
strings
,
indices
must always be integers. A
float
with a decimal part of zero is not a valid index. This is the first time we absolutely need the int function to convert floats into integers. This could be the case in a scenario where a program is picking
items
from a list using some form of mathemagics involving floats (could be as simple as the middle value from a list with odd length). In this scenario it would be mandatory to convert the result into an integer before it could be used as a list index.
Subscription
can be used in achieving what we wanted:
Enter value and unit to convert: 12 yd
12.000 yd is 10.973 m
Using subscription with indices we can pick each item from the list produced by the split
method
. For example, we could
assign
them to
variables
.
value_unit = input("Enter value and unit to convert: ").split(" ")
value = value_unit[0]
unit = value_unit[1]

Sherlock de Bug and His Arch-Nemesis

One very common arch-nemesis with inputs is to forget that it's always returned as a string. Sometimes this error can travel in the code quite far before the program finally crashes.
Learning goals: Which
exception
occurs when a number
input
is used in calculations without converting it. How to change input handling to avoid the problem.

Introduction:
Let's reproduce the lines from the above in the
Python console
:
In [1]: value_unit = input("Enter value and unit to convert: ").split(" ")
Enter value and unit to convert: 12 m
In [2]: value = value_unit[0]
Try to do some calculation with the value variable that's not muliplication (e.g. subtraction).

Answer Specification:
The calculation should go wrong with a certain exception. The answer should be this exception's name. You also need to solve the problem. As the second line of your answer, you need to rewrite the second line from the example in a way that value variable becomes usable in calculations.
In the answer box, type what error you receive. On the second line you need need to fix the second line so that value becomes a real number.
Warning: You have not logged in. You cannot answer.

Sherlock de Bug and The Mystery of the Lost Index

In addition to the programmer being their own arch-nemesis in input processing, the user is a close second. Our current example assumes that a user is able to give both value and unit, but what happens when they don't?
Learning goals: What's another common
exception
when we trust user's ability to give proper
input
too much.

Introduction:
We're doing this just like in the previous task, but this time the third line from the example is also included. In addition we're going to simulate a user who inputs a value without unit.
In [1]: value_unit = input("Enter value and unit to convert: ").split(" ")
Enter value and unit to convert: 12
In [2]: value = value_unit[0]
In [3]: unit = value_unit[1]

Answer Specification:
One of these lines causes an exception. The answer is two lines: the name of the exception, and the line of code that caused the exception. Copy the line to the answer.
Two lines: exception name first, line of code second.
Warning: You have not logged in. You cannot answer.
There's also a more direct way to assign the results of split to variables:
value, unit = input("Enter value and unit to convert: ").split(" ")
This way works best when the values are needed as
strings
. With this we would need one extra line to convert the value to a
float
. You should also note that using this form of assignment results in a different
exception
if the split doesn't result in a
list
with the expected length:
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
 in 
----> 1 value, unit = input("Enter value and unit to convert: ").split(" ")

ValueError: not enough values to unpack (expected 2, got 1)
When strings are partitioned it's always important to check that the split produces the correct number of results. So if we want to ask both value and unit at the same time, the prompt function needs some changes. We need to add one new except
branch
to the try structure. This isn't very revolutionary - it's very similar to adding more elif branches to a
conditional structure
. It turns out that try structures can have an indefinite number of excepts. Furthemore like conditional structures, only the first except branch that matches the encountered Exception is executed. In addition to changing the exception handling, the function must now
return
two values.
def prompt_value_and_unit():
    while True:
        try:
            value_unit = input("Enter value and unit to convert: ").split(" ")
            value = float(value_unit[0])
            unit = value_unit[1]
        except ValueError:
            print("Value must be a plain number")
        except IndexError:
            print("You must enter the value and its unit separated by a space")
        else:
            break
    return value, unit
Because it now has two return values, the
function call
on the other end must also be modified. We've also changed the function's name to be more descriptive of what it does. The function call would look like this:
value, unit = prompt_value_and_unit()
We went through the trouble of developing this, but we're actually not going to use it. It would introduce new problems, particularly because we used to use the unit input for determining when to go back to the main menu. We could make it work but there isn't much to learn in the process right now. We'll just leave it here as an example of how to handle exceptions when prompting multiple values from an input with the split method.

A Compilation of Lists

We've come as far as we can with the unit converter. We're moving on to a new example: a command line program that is used for managing collections. The example itself is for managing music album collections but is easily adaptable for some other collectibles. The basic features of the program are adding, removing and modifying albums.
Learning goals: This section teaches you more about lists - particularly how to add things to them. You'll also learn that lists are mutable and what it means in practice. Comment lines are also introduced officially, and we'll show how they can be used to make the code easier to read.

Requesting Comment

There are situations - quite often - when real code is not yet available and some sort of replacement is called for. These replacements should look like the real thing from the outside. In our example we should already introduce two
functions
: load_collection and save_collection. The latter can just do literally nothing with the pass keyword as its sole content. The first one should return a
list
that represents the collection, with a few sample albums inside it. This way we can implement the rest of the program even though we don't have real data.
At this moment we also need to decide what the collection data will look like. We're going to agree on five fields for each album: artist, album title, number of tracks, total length, and release year. Because these fields have distinct names,
dictionary
is an ideal fit for representing them. Like this:
{
    "artist": "Monolithe",
    "album": "Nebula Septem",
    "no_tracks": 7,
    "length": "49:00",
    "year": 2018
}
Image source 4
Until we have actual albums in the collection, we can use
comments
to remind us what keys were agreed upon. Comments are lines in a code file that the
Python interpreter
ignores entirely when it's reading the code. They can therefore contain additional information for the human who is reading the code, like for your future self. They can also be used in planning: we can write a short description of what unimplemented parts of the code are supposed to do when they're ready. When doing this it's possible to skip some details at the start of the project, and still be able to come back and actually remember what it should eventually do. Comments can also act as reminders about what
data structures
contain:
def load_collection():

    # keys:
    # artist, album, no_tracks, length, year
    collection = []
    return collection
The lines beginning with # are comments. When Python encounters this character outside a
string
it immediately stops reading the line and moves on to the next one. The code example above contains just three lines that are executed: function definition, creating an empty list, and
returning
said list.
Comments
are also useful in solving bugs in the program. By temporarily putting the comment character at the beginning of an existing line of code, the line's execution can be skipped without having to entirely delete it. This can also sometimes be used to skip broken lines to see if rest of the program works as intended.
Comments also have a relative,
documentation string
, or docstring as we're going to call it. The use of docstrings is more standardized than comments. A docstring is typically attached to a
function
. It is, in fact, that exact
string
you will see when using the help function in the
Python console
. At minimum a docstring should describe what the function does, what
arguments
it expects/accepts and what it
returns
. A docstring is usually demilited with triple quotes and it must be immediately below the function definition line before any actual code lines.
def load_collection():
    """
    Creates a test collection. Returns a list that contains dictionaries of
    five key-value pairs.
    Dictionary keys match the following information:
    "artist" - name of the album artist
    "album" - title of the album
    "no_tracks" - number of tracks
    "length" - total length
    "year" - release year
    """

    # keys:
    # artist, album, no_tracks, length, release_year
    collection = []
    return collection
If we write a
main program
with one line, help(load_collection), the code will have the following output when it's ran:
Help on function load_collection in module __main__:

load_collection()
    Creates a test collection. Returns a list that contains dictionaries of
    five key-value pairs.
    Dictionary keys match the following information:
    "artist" - name of the album artist
    "album" - title of the album
    "no_tracks" - number of tracks
    "length" - total length
    "year" - release year
This looks quite familiar. Using
docstrings
is an extremely good habit, especially if someone else will look at your code - including future you who may not recall what you were thinking when writing the code. In this course this is holds especially for the course projects that are checked by assistants manually by reading your code. In bigger projects docstrings can also be used in combination with specific documentation tools. One such tool is Sphinx that can create very neat documentation pages from docstrings that use a certain syntax.
Before moving on, let's add a
stub
function for save_collection, and add some albums to the
list
returned by the load_collection function. Only part of the test collection definition is shown below - defining a list that contains dictionaries becomes quite a few lines of code after all. The comment about the fields can now be removed since the same information is contained in the docstring.
def load_collection():
    """
    Creates a test collection. Returns a list that contains dictionaries of
    five key-value pairs.
    Dictionary keys match the following information:
    "artist" - name of the album artist
    "album" - title of the album
    "no_tracks" - number of tracks
    "length" - total length
    "year" - release year
    """

    collection = [
        {
            "artist": "Alcest",
            "album": "Kodama",
            "no_tracks": 6,
            "length": "42:15",
            "year": 2016
        },
        {
            "artist": "Canaan",
            "album": "A Calling to Weakness",
            "no_tracks": 17,
            "length": "1:11:17",
            "year": 2002
        },
        {
            "artist": "Deftones",
            "album": "Gore",
            "no_tracks": 11,
            "length": "48:13",
            "year": 2016
        },
        # rest is cut, the code example itself defines 8 more
    ]
    return collection

def save_collection(collection):
    pass
Now we can create a
main program
draft where the user can select the program's basic functions, and add corresponding stub functions.
def add(collection):
    pass

def remove(collection):
    pass

def show(collection):
    pass

collection = load_collection()
print("This program manages an album collection. You can use the following features:")
print("(A)dd new albums")
print("(R)emove albums")
print("(S)how the collection")
print("(Q)uit")
while True:
    choice = input("Make your choice: ").strip().lower()
    if choice == "a":
        add(collection)
    elif choice == "r":
        remove(collection)
    elif choice == "s":
        show(collection)
    elif choice == "q":
        break
    else:
        print("The chosen feature is not available.")
save_collection(collection)
The collection is loaded at the beginning of the program, and (if the function did anything) saved at the end. We've also added a stub for each function that is called in the main program so that the code can be executed. Docstrings have been left out because we are about to implement the functions.

Lists Growing Before Your Eyes

Unlike
dictionaries
,
lists
do not support adding new
values
by assigning to a non-existing
index
. The example shows adding a new key-value pair to a dictionary, and then what happens if a similar operation is attempted for lists:
In [1]: d = {"a": 1, "b": 2, "c": 3}
In [2]: d["d"] = 4
In [3]: d
Out[3]: {'a': 1, 'b': 2, 'c': 3, 'd': 4}
In [4]: numbers = [213, 12, 45]
In [5]: numbers[3] = 53
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-5-8f3b48cbce55> in <module>
----> 1 numbers[3] = 53

IndexError: list assignment index out of range
If this doesn't work, what does? Put very shortly,
items
are added to lists using the append
method
. It appends a new item to the end of the list. Short explanation, short example:
In [1]: numbers = [213, 12, 45]
In [2]: numbers.append(34)
In [3]: print(numbers)
[213, 12, 45, 34]
The difference is largely due to how list items exist in an order defined by their indices. The indices are managed by the list itself, so the coder doesn't need to know the exact place where the new item will end up. Meanwhile, in dictionaries, the keys are arbitrary, and therefore each key must be explicitly specified - Python cannot guess what the key should be. On the other hand, these two are similar in the sense that they are both
mutable
types. This means that appending does not create a new copy of the list. Likewise, if multiple variables contain the same list, the added item will appear in all of them. This is also the first time in the course where a new reference is created without the
assignment operator
.

Sherlock de Bug and The Secret of the Lost Evidence

When adding things to strings we always had to assign the result back to a variable (usually the same variable). Maybe we should do that with lists too, just in case?
Learning goals: What happens when the
return value
of the append
method call
is
assigned
to a
variable
.

Introduction:
Let's go through the following process in the
Python console
. Before trying it out, think about what this code should print.
In [1]: evidence = ["fingerprint", "knife", "Eeyore plushie"]
In [2]: evidence = evidence.append("imgur username")
In [3]: print(evidence)

Answer Specification:
The answer we're looking for is the output from the print call. If the result seems puzzling to you, we recommend paying careful attention to the following section in the material.
Enter the result you get from the interpreter.
Warning: You have not logged in. You cannot answer.
Image source 5
Let's see what the help function tells us about append:
append(...) method of builtins.list instance
    L.append(object) -> None -- append object to end
Typically these help texts show a
function
or
method's
return value
's
type
on the right side of the arrow. In this case the return value is None which is a special value that means "nothing". It's an empty
object
that is only equal to itself, and its
boolean
equivalent is False. Functions and methods that do not contain a return statement, or have no values in their return statement, will implicitly return None.
Because
lists
are
mutable
just like dictionaries, adding values also behaves similarly. The animation illustrates this process for lists.
There does exist a way to add new values to a list so that a new list is created. This can be done with the + operator, putting two lists together to form a new one:
In [1]: numbers_1 = [1, 2, 3]
In [2]: numbers_2 = numbers_1
In [3]: numbers_2 = numbers_2 + [4]
In [4]: print(numbers_1, numbers_2)
[1, 2, 3] [1, 2, 3, 4]
This is not seen very often because needless copying lists is a bit expensive, but mostly because in most cases it's far more practical that all parts of the program access the same list. So it is in our collection management program. When the add
function
adds new album to the collection, the added albums will be visible in the
main program
as well as any other functions, and we don't need to worry about accidentally using an outdated copy of the list. For the same reason, the add function doesn't need to
return
the list - it manipulates the one and only list we have in memory, the one that was loaded with the load_collection function.

Adding Nothing

Appending items to lists during program execution is very common in programming. Let's imagine a software that processes measurements and gathers them into a list. Whenever there is invalid value, zero should be placed in its stead. In this exercise we'll practice adding a zero to an existing list.
Learning goals: Practice how
items
should be added to
lists
the right way.

Introduction:
Start by defining a list variable that contains some measurements:
In [1]: measurements = [12.3, 44.51, 133.7]

Answer Specification:
Your task is to write a single line of code that adds 0.0 to this list. The addition must be done without creating a new copy of the list.
Type your answer below.
Warning: You have not logged in. You cannot answer.
With this information we're able to implement the add function.
def add(collection):
    print("Fill the information for a new album. Leave album title empty to stop.")
    while True:
        title = input("Album name: ")
        if not title:
            break

        artist = input("Artist name: ")
        no_tracks = prompt_number("Number of tracks: ")
        length = prompt_time("Total length: ")
        year = prompt_number("Release year: ")
        collection.append({
            "artist": artist,
            "album": title,
            "no_tracks": no_tracks,
            "length": length,
            "year": year
        })
        print("Album added")
This
function
adds new albums until the user
inputs
an empty album name. The new thing we've learned is shown in the append
method call
that we've split into multiple lines. It adds a new dictionary with the album information to the collection
list
. Note also the lack of return in the function. It's not needed because, like we just learned, the function modifies an existing list. The code also shows calls to two functions that don't exist yet. Of these two, prompt_number is a close relateive to the prompt_value function from earlier:
def prompt_number(prompt):
    while True:
        try:
            number = int(input(prompt))
        except ValueError:
            print("Input an integer")
        else:
            return number
There are two differences: first of all, this is used for number of tracks and release year, so it makes more sense to only accept integers. Second is the bigger change: we've changed the input function's
argument
from a
literal
string
to a
variable
. Doing this allows us to use the same function for prompting all integers in the program. The prompt string will now be provided as an argument when this function is called. This is a very useful trick for any program that has several similar prompts (like this one where we prompt integers repeatedly). The try structure that looks out for
exceptions
is only needed in one place, but at the same time we can still change the prompt that is shown to the user by changing the argument.
We're going to leave the prompt_time function as a stub for now. The validity of time input is pondered later.
def prompt_time(prompt):
    return input(prompt)
With all of this, the function is pretty neat:
This program manages an album collection. You can use the following features:
(A)dd new albums
(R)emove albums
(S)how the collection
(Q)uit
Make your choice: a
Fill the information for a new album. Leave album title empty to stop.
Album name: Lead and Aether
Artist name: Skepticism
Number of tracks: 12.5
Input an integer
Number of tracks: 6
Total length: 47:49
Release year: 1997
Album added
Album name: 
Make your choice: q

Order of Measures

Adding items one by one is usually done with the append method like we just learned. However, there are situations where we want to add more than value to a list at once, for instance the contents of another list. Append is useless in this case because it would add the second list as a single item inside the first list... So what's more useful?
Learning goals: You'll learn a way to add multiple
items
to in existing
list
in one go.

Introduction:
We've provided you with a couple of lists consisting of entirely made up measurements: one contains old measurements, the other is a batch of new ones that should be added to the old ones.
In [1]: measurements = [12.3, 44.51, 133.7, 0.0]
In [2]: batch = [45.2, 15.2, 7.89]
You may also want to look at list documentation. One way to access it is to use the help function:
In [3]: help([])

Answer Specification:
Your task is to use the documentation to figure out which method should be used for adding multiple items to the end of a list. You may encounter the word iterable in the documentation. This is a common name for all
sequence-like
objects
- which includes lists.
The answer itself should be one line of code that adds the items from the batch list to the end of the measurements list so that the result looks like this:
In [5]: measurements
[12.3, 44.51, 133.7, 0.0, 45.2, 15.2, 7.89]
Please remember that using the +
operator
with lists creates a new list. It isn't the correct answer in this case!
Type the line of code, that does this.
Warning: You have not logged in. You cannot answer.

Looping with Abandon

In our next episode lists get new friends: loops that can iterate through them. Our goal here is to implement one feature: printing of lists.
Learning goals: After this section you know what for loops are and how they are connected to lists. We'll also show you a new string method that can make really pretty prints.

Runthrough

We'll start with printing because it is a bit gentler introduction to
for loops
. The goal is to implement the contents of the show
function
in our example program. The very first thing to try is to see what happens if we just print the
list
.
def show(collection):
    print(collection)
That seems easy. Did we really need a section for this? Well, yes and no, but mostly yes. As you can see the results are not particularly pleasing to read (manual line splitting was done at 80 characters):
This program manages an album collection. You can use the following features:
(A)dd new albums
(R)emove albums
(S)how the collection
(Q)uit
Make your choice: s
[{'artist': 'Alcest', 'album': 'Kodama', 'no_tracks': 6, 'length': '0:42:15', '
year': 2016}, {'artist': 'Canaan', 'album': 'A Calling to Weakness', 'no_tracks
': 17, 'length': '1:11:17', 'year': 2002}, {'artist': 'Deftones', 'album': 'Gor
e', 'no_tracks': 11, 'length': '0:48:13', 'year': 2016}, {'artist': 'Funeralium
', 'album': 'Deceived Idealism', 'no_tracks': 6, 'length': '1:28:22', 'year': 2
013}, {'artist': 'IU', 'album': 'Modern Times', 'no_tracks': 13, 'length': '0:4
7:14', 'year': 2013}, {'artist': 'Mono', 'album': 'You Are There', 'no_tracks':
6, 'length': '1:00:01', 'year': 2006}, {'artist': 'Panopticon', 'album': 'Roads
to the North', 'no_tracks': 8, 'length': '1:11:07', 'year': 2014}, {'artist': '
PassCode', 'album': 'Clarity', 'no_tracks': 13, 'length': '0:49:27', 'year': 20
19}, {'artist': 'Scandal', 'album': 'Hello World', 'no_tracks': 13, 'length': '
0:53:22', 'year': 2014}, {'artist': 'Slipknot', 'album': 'Iowa', 'no_tracks': 1
4, 'length': '1:06:24', 'year': 2001}, {'artist': 'Wolves in the Throne Room',
'album': 'Thrice Woven', 'no_tracks': 5, 'length': '0:42:19', 'year': 2017}]
appropriate reaction:
Image source 6
A more desirable result would look something like this:
1.  Alcest - Kodama (2016) [6] [42:15]
2.  Canaan - A Calling to Weakness (2002) [17] [1:11:17]
3.  Deftones - Gore (2016) [11] [48:13]
4.  Funeralium - Deceived Idealism (2013) [6] [1:28:22]
5.  IU - Modern Times (2013) [13] [47:14]
6.  Mono - You Are There (2006) [6] [1:00:01]
7.  Panopticon - Roads to the North (2014) [8] [1:11:07]
8.  PassCode - Clarity (2019) [13] [49:27]
9.  Scandal - Hello World (2014) [13] [53:22]
10. Slipknot - Iowa (2001) [14] [1:06:24]
11. Wolves in the Throne Room - Thrice Woven (2017) [5] [42:19]
Each album on their own line without any messy braces or quotes. We know that by default each print call in the code produces one line in the output. The logical conclusion would be to
call
print for each
item
in the
list
separately. This material has also shown us that repetition is usually done with
loops
. However, so far we only know of
while loops
, that are generally used when the number of iterations cannot be deduced in advance. In our current case the number of iterations can be deduced: the program can count the number of items in the list before looping through it.
Python uses
for loops
specifically for these cases. Their expertise is in going through lists and other
sequences
. These also share a common name: iterable, which hints at how they are
objects
that can be iterated through. There's a wide variety of these. Lists are a given, but there's also
strings
and
tuples
, the latter of which we'll introduce properly later. In addition to these iterable types, there are iterable special objects like
generators
and
enumerate
.
Python's for loop executes all of the statements contained within it for each
item
in a given iterable. A very typical use case is to apply an operation or series of operations to each item in a
list
. It fits like a glove for printing each item from a list. Before applying it to our more complex example list, let's examine some details. We'll use the simplest possible example in the console:
In [1]: animals = ["dog", "cat", "squirrel", "walrus", "donkey", "llama"]
In [2]: for animal in animals:
   ...:     print(animal)
   ...:
dog
cat
squirrel
walrus
donkey
llama
If nothing else this example proves that a for loop indeed does repeat the statement(s) contained within for each item in the target list. The loop itself is declared as follow, by starting a line with the proper
keyword
:
for animal in animals:
In addition to the for keyword itself, the in
operator
is also a mandatory part of a for loop declaration. This statement can be read as "for each animal in the animals sequence". Just like
functions
have their named
parameters
, this example also has something similar: the animal
variable
- we'll call it
loop variable
- represents the current item of the list on each iteration. It gets the values "dog", "cat", "squirrel", "walrus", "donkey", and "llama", in this order, during the loop's execution. The value changes on each iteration.
Image source 7
3
The animation also shows a small side detail: the
loop variable
does not cease to exist at the end of the loop - it just retains its last value. In this sense it is markedly different from
function
parameters
that only exist for the function's lifetime. There's no real use cases for this feature, it's just something to keep in mind to avoid nasty surprises. The best practice is to always use loop variable names that do not overlap with other names inside the function's
scope
in
global scope
.

Lonely Vector in the Multiverse

Unit vectors are practical creatures whether there's two or seventeen dimensions. They can be used e.g. to represent the direction of a moving object. In this task you'll be working on a function that creates a unit vector from any vector. Unit vector is a vector with length of 1. The components of a unit vector can be obtained by dividing each component of the vector with the vector's length.
Learning goals: Constructing a new
list
from another list using a
loop
. Forming a unit vector.

Introduction:
In this task we have a function that creates a unit vector from a vector. Download the code template from resources and write the missing lines in place of the comments as instructed.
Because the function doesn't know how many dimensions each vector will have, the only option is to make a
for loop
. The original vector is in the v
variable
, and it is a list of the vector's components. The vector's length is in the length variable.
Your task is to write a loop that iterates through the original vector, divides each component by the vector's length, and then appends the result into a new list in the u variable. Use component as the name of the
loop variable
. Use the append method. Note that single character variable names are perfectly valid here because they are also used in vector math.

Answer Specification:
When you have a working solution, copy the two lines you wrote in place of the comments into the answer box.

Resources:
vector.py
def calculate_length(v):
    square = 0
    for component in v:
        square += component ** 2
    return square ** 0.5
    
def to_unit_vector(v):
    u = []
    length = calculate_length(v)
    # loop declaration
    # loop content block (1 line)
    return u
    
print(to_unit_vector([2.0, 2.0, 2.0, 2.0]))


Warning: You have not logged in. You cannot answer.
By now we know how to declare a
for loop
, and how its
loop variable
can be used to do things to
items
in a
list
. Let's try to put this loop tech into our show
function
to print each item separately.
def show(collection):
    for album in collection:
        print(album)
With this the print looks like
{'artist': 'Alcest', 'album': 'Kodama', 'no_tracks': 6, 'length': '42:15', 'year': 2016}
{'artist': 'Canaan', 'album': 'A Calling to Weakness', 'no_tracks': 17, 'length': '1:11:17', 'year': 2002}
{'artist': 'Deftones', 'album': 'Gore', 'no_tracks': 11, 'length': '48:13', 'year': 2016}
{'artist': 'Funeralium', 'album': 'Deceived Idealism', 'no_tracks': 6, 'length': '1:28:22', 'year': 2013}
{'artist': 'IU', 'album': 'Modern Times', 'no_tracks': 13, 'length': '47:14', 'year': 2013}
{'artist': 'Mono', 'album': 'You Are There', 'no_tracks': 6, 'length': '1:00:01', 'year': 2006}
{'artist': 'Panopticon', 'album': 'Roads to the North', 'no_tracks': 8, 'length': '1:11:07', 'year': 2014}
{'artist': 'PassCode', 'album': 'Clarity', 'no_tracks': 13, 'length': '49:27', 'year': 2019}
{'artist': 'Scandal', 'album': 'Hello World', 'no_tracks': 13, 'length': '53:22', 'year': 2014}
{'artist': 'Slipknot', 'album': 'Iowa', 'no_tracks': 14, 'length': '1:06:24', 'year': 2001}
{'artist': 'Wolves in the Throne Room', 'album': 'Thrice Woven', 'no_tracks': 5, 'length': '42:19', 'year': 2017}
This is markedly better but still a far cry from the beautiful printout we had planned.

List Exposure

Printing
lists
and other
data structures
is always a challenge, and the best solution will always depend on what we want the program to do. One factor that limits options is list length. If the length is not fixed, the ways in which it can be printed are more limited. In our case the length of the collection list does vary, and for that we print it with a
loop
. For the dictionaries contained within the list we can use
f strings
.
def show(collection):
    for album in collection:
        print(
            f"{album['artist']}, {album['album']}, {album['no_tracks']}, "
            f"{album['length']}, {album['year']}"
        )
This is one step closer to the desired output but there's still something missing, like the ordinals at the beginning of each line. One way to add them would be to introduce a counter inside the loop:
def show(collection):
    ordinal = 1
    for album in collection:
        print(
            f"{ordinal:2}. "
            f"{album['artist']}, {album['album']}, {album['no_tracks']}, "
            f"{album['length']}, {album['year']}"
        )
        ordinal += 1
In other words we introduce an integer variable with an initial value of 1, and then we add 1 to it on each iteration. However, there is a more convenient way to make
indices
available inside a for loop. The ordinal is basically the same as the index of an item, + 1. Let's write the code first and wonder about it after:
def show(collection):
    for i, album in enumerate(collection):
        print(
            f"{i + 1:2}. "
            f"{album['artist']}, {album['album']}, {album['no_tracks']}, "
            f"{album['length']}, {album['year']}"
        )
First question: what is the enigmatic enumerate? The answer, as usual, can be figured out in the
Python console
. Our example has a bit too much stuff per item, so let's examine using the animal list from earlier:
In [1]: animals = ["dog", "cat", "squirrel", "walrus", "donkey", "llama"]
In [2]: enumerate(animals)
Out[2]: <enumerate at 0x7fe27e0e3168>
That's, uh, useful information. It turns out enumerate produces a
generator
-like object that can be iterated with a loop but isn't a
data structure
. It's actually a function that produces the next value in a sequence each time it's called. We don't do much with generators right now, but they - and enumerate - can be converted into lists. Take 2:
In [3]: list(enumerate(animals))
Out[3]:
[(0, 'dog'),
 (1, 'cat'),
 (2, 'squirrel'),
 (3, 'walrus'),
 (4, 'donkey'),
 (5, 'llama')]
The values contained within braces inside the list are data structures called
tuples
. We haven't talked about them yet. Luckily there isn't much to tell either: they are an
immutable
version of lists. It can be read like a list but it cannot be changed, basically. If we iterate through a list that contains tuples, on each iteration the
loop variable
is assigned a tuple as its value. However, it's perfectly legal to have multiple loop variables, and it works just like a
function call
that stores multiple return values. In other words, when we know with certainty that each
item
in the list contains two items, they can be split into two variables like we already did in the example. The same with animals:
In [4]: for i, animal in enumerate(animals):
   ...:     print(f"{i}. {animal}")
   ...:
0. dog
1. cat
2. squirrel
3. walrus
4. donkey
5. llama
This shows that both i and animal have new values on each loop
iteration
. The chosen
loop variable
name, i, is a typical choice in loops like this in pretty much all programming langugages. If there's multiple nested loops, the next picks are j and then k. Of course using longer names is also allowed.
Shown below are two different ways to write the same functionality. This should help in understanding what's going on in the enumerate example. Shown first is splitting the loop variable on a separate line instead of using two loop variables. This adds one extra line:
In [5]: for item in enumerate(animals):
   ...:     i, animal = item
   ...:     print(f"{i}. {animal}")
Shown second is using
subscription
on the print line itself. This makes the print line itself less readable:
In [6]: for item in enumerate(animals):
   ...:     print(f"{item[0]}. {item[1]}")

Inventory Engineering

A simple inventory management program handles a list that contains names of items and their quantities. In cases like this it's usually handy to give each value their own name in the loop declaration. For this reason Python supports multiple loop variables.
Learning goals: Writing a
for loop
declaration that uses two
loop variables
.

Introduction:
Because this is once again part of a more complex implementation, we've given you a code template as a resource. Replace the
commented
line with a
loop
declaration that does what is asked for in this task. As you can see from the template, the
list
contains
tuples
of two items. Both items from the tuple need to be assigned to their own loop variables, let's call them name and qty.
You know your loop has been declared correctly when you get the following output:
Storage contains 12 x donkey
Storage contains 1 x Moomin mug
Storage contains 4 x poleax

Answer Specification:
When your solution works, copy the loop declaration line into the answer box. There should be exactly one line.

Resources:
inventory.py
inventory = [("donkey", 12), ("Moomin mug", 1), ("poleax", 4)]

# loop declaration here
    print(f"Storage contains {qty} x {name}")

Write the loop declaration into the answer box
Warning: You have not logged in. You cannot answer.
There's one more technique to printing lists that's particularly neat when we want to print lists of unknown length to one line. For a simple example, let's consider a program where the user
inputs
some words one by one. The words are put into a list and one of the program's features is to print out all of the words. Because the number of words in the list is not fixed, formatting cannot be used - we wouldn't know how many
placeholders
to use. Not to worry, there's another
method
that is perfectly suitable for this scenario: join. Using it looks a bit odd compared to what we've seen so far.

Commatose

Learning goals: What does the result printed using the join
method
look like.

Introduction:
Type the following lines in to the
Python console
:
In [1]: animals= ["dog", "cat", "squirrel", "donkey", "walrus", "llama"]
In [2]: print(",".join(animals))

Answer Specification:
Copy the output of the print to the answer box.
Copy the output you receive in the answer box below.
Warning: You have not logged in. You cannot answer.
In more specific terms, the join method works by joining together
items
from a
list
(or another sequence) by using a
string
as a "connector". In this sense it's like the reverse of split. Also like split, join is a string method. This is why the
syntax
when using it can look a bit unintuitive: the connector string is first on the line, and the list itself isn't seen until we get into the
method call
arguments. The reason they put it this way is most likely the fact that while join can be used for any
sequences
, the connector must always be a string - therefore the method has been attached to the string type rather than implementing it for each sequence type separately.
The join method is often so handy that it can also be used for lists with a fixed length. In addition to producing generally more compact code than a format, join is also more dynamic and therefore far less likely to break due to changes elsewhere in the code. Our collection program uses
dictionaries
but we could join if we also used the values method for each dictionary to retrieve the values without the keys. Almost:
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/media/sf_virtualshare/OA/M3/collection.py in <module>
    148         remove(collection)
    149     elif choice == "s":
--> 150         show(collection)
    151     elif choice == "q":
    152         break

/media/sf_virtualshare/OA/M3/collection.py in show(collection)
    133     ordinal = 1
    134     for i, album in enumerate(collection):
--> 135         print(f"{i + 1:2}. {', '.join(album.values())}")
    136 
    137 collection = load_collection()

TypeError: sequence item 2: expected str instance, int found
This shows an important restriction regarding join: all
items
in the
list
(or other sequence) must be
strings
. We have two potential solutions to this issue: a) use another way; b) convert all items in the list to strings before joining them. It would also be possible to just include all numbers in the dictionary as strings but then they would no longer be valid for calculations (if we had any planned). Once again it depends on the context what the best option is.

Would Someone Please Think of the Spaces

There is a severe flaw in the join example from the previous task: there are no spaces after commas. Fortunately this is easy to fix because join doesn't limit how long the connector string can be.
Learning goals: Using the join
method
.

Introduction:
The starting situation is the same as in the last task, we have a list of animals:
In [1]: animals= ["dog", "cat", "squirrel", "donkey", "walrus", "llama"]

Answer Specification:
The answer should be a line of code that prints this
list
so that there is a comma and a space between each
item
, in accordance to good manners. Once you have achieved the desired output in the
console
, copy the code line that produced it to the answer box.
Write the fixed row below.
Warning: You have not logged in. You cannot answer.
Our example program will go back to the solution that used format:
def show(collection):
    for i, album in enumerate(collection):
        print(
            f"{i + 1:2}. "
            f"{album['artist']}, {album['album']}, {album['no_tracks']}, "
            f"{album['length']}, {album['year']}"
        )

New World Order

This is what we got so far for our catalog program. If you've followed the code's progress by updating your own version of it when we've made changes, you should have a similar code on your computer. You may have defined the functions in a different order, but everything else should be the same.
def prompt_number(prompt):
    while True: 
        try:
            number = int(input(prompt))
        except ValueError:
            print("Input an integer")
        else:
            return number

def prompt_time(prompt):
    return input(prompt)

def load_collection():
    """
    Creates a test collection. Returns a list that contains dictionaries of
    five key-value pairs.
    Dictionary keys match the following information:
    "artist" - name of the album artist
    "album" - title of the album
    "no_tracks" - number of tracks
    "length" - total length
    "year" - release year
    """

    collection = [
        {
            "artist": "Alcest",
            "album": "Kodama",
            "no_tracks": 6,
            "length": "42:15",
            "year": 2016
        },
        {
            "artist": "Canaan",
            "album": "A Calling to Weakness",
            "no_tracks": 17,
            "length": "1:11:17",
            "year": 2002
        },
        {
            "artist": "Deftones",
            "album": "Gore",
            "no_tracks": 11,
            "length": "48:13",
            "year": 2016
        },
        # rest is cut, the code example itself defines 8 more
    ]
    return collection

def save_collection(collection):
    pass

def add(collection):
    print("Fill the information for a new album. Leave album title empty to stop.")
    while True:
        title = input("Album name: ")
        if not title:
            break

        artist = input("Artist name: ")
        no_tracks = prompt_number("Number of tracks: ")
        length = prompt_time("Total length: ")
        year = prompt_number("Release year: ")
        collection.append({
            "artist": artist,
            "album": title,
            "no_tracks": no_tracks,
            "length": length,
            "year": year
        })
        print("Album added")

def remove(collection):
    pass

def show(collection):
    for i, album in enumerate(collection):
        print(
            f"{i + 1:2}. "
            f"{album['artist']}, {album['album']}, {album['no_tracks']}, "
            f"{album['length']}, {album['year']}"
        )

collection = load_collection()
print("This program manages an album collection. You can use the following features:")
print("(A)dd new albums")
print("(R)emove albums")
print("(S)how the collection")
print("(Q)uit")
while True:
    choice = input("Make your choice: ").strip().lower()
    if choice == "a":
        add(collection)
    elif choice == "r":
        remove(collection)
    elif choice == "s":
        show(collection)
    elif choice == "q":
        break
    else:
        print("The chosen feature is not available.")
save_collection(collection)
In terms of how much code there is, this is like a third or half of the course project size. Our next mission is to implement a new feature that leads us to new things in the domain of lists: sorting and slicing content. Let's add a new function we can start to work on:
def organize(collection):
    pass
We can also already add this feature to the main menu:
collection = load_collection()
print("This program manages an album collection. You can use the following features:")
print("(A)dd new albums")
print("(R)emove albums")
print("(S)how the collection")
print("(O)rganize the collection")
print("(Q)uit")
while True:
    choice = input("Make your choice: ").strip().lower()
    if choice == "a":
        add(collection)
    elif choice == "r":
        remove(collection)
    elif choice == "s":
        show(collection)
    elif choice == "o":
        organize(collection)
    elif choice == "q":
        break
    else:
        print("The chosen feature is not available.")
save_collection(collection)
Learning goals: We'll investigate how lists can be organized with the sort method and suitable helper functions. We'll also learn some new things about how strings are sorted.

Order Please

Image source 8
We need to sort our collection. What's more, we want to make it possible for the user to select the field to sort by and whether they want the sorting in ascending or descending order. All of this can be done with
list
method
sort.
In [1]: list_1 = [37, 5, 12]
In [2]: list_1.sort()
In [3]: list_1
Out[3]: [5, 12, 37]
By itself this method sorts the list's
items
in an ascending order. In other words, smallest item first, and biggest item last. It's pretty easy to understand for numbers how it works. For strings, ordering is based on alphabetical order:
In [1]: animals = ["walrus", "duck", "donkey", "llama", "koala", "dromedary", "moose"]
In [2]: animals.sort()
In [3]: animals
Out[3]: ['donkey', 'dromedary', 'duck', 'koala', 'llama', 'moose', 'walrus']
The ordering of
lists
is based on the first item of each list by default. And, if the first items are the same, the second items are looked at, and so on. However, our collection contains dictionaries. Trying to sort them without any additional arguments to sort causes a TypeError
exception
. For this reason the sort
method
has an
optional argument
called key. This argument accepts a
function
that is used for deriving a comparison value from each
item
before the sorting itself is done. Let's start by looking at a simple example, using a builtin Python function in this role. Sometimes you get interesting results when sorting lists that contain numbers as
strings
:
In [1]: numbers = ["2", "12", "5", "43", "48"]
In [2]: numbers.sort()
In [3]: numbers
Out[3]: ['12', '2', '43', '48', '5']
If the goal was to sort numbers based on their numerical value, this is obviously not the desired outcome. This can be fixed by using the int function as the key argument:
In [4]: numbers.sort(key=int)
In [5]: numbers
Out[5]: ['2', '5', '12', '43', '48']
This is the first time the entire learning material where we use a
function's
name in real code without it being followed by parentheses to
call
it. This a specific mechanism in programming called
callback
. In this mechanism, instead of calling a function normally, the function is provided to another part of the program to tell that part which function it should call when the time comes. In order for callbacks to work, the function must always have the number and types of arguments and return values that's expected by the part of the program that needs to call it.
In this case the part of the program that will call the function is the sort method. Its key argument can be used for defining a callback. The method will call whichever function has been assigned to its key parameter when it needs a
comparison value
for each item in the list. In this case the callback function must be one that receives exactly one argument and
returns
exactly one value. Python doesn't come with a function that would fit our purposes. We need a function that chooses one field from a dictionary to represent the whole dictionary.
Since the function we provide as the key argument can only have one argument (the item), we cannot create a function that receives the sorting field as an argument. The only way that we currently have for implementing this is to create a function for each separate field. It's not ideal but with what we know it's the best we can do. If you're interested in better solutions, you can always find them in the Python documentation. These helper functions that our code will use as key arguments are rather simple:
def select_artist(album):
    return album["artist"]
The function returns the value of the "artist" key of each dictionary to be used in sorting. The other four are similar:
def select_title(album):
    return album["album"]

def select_no_tracks(album):
    return album["no_tracks"]

def select_length(album):
    return album["length"]

def select_year(album):
    return album["year"]

Inventory Picker

Once again we return to the wonderful world of inventory management. This time the task is to create a function that will be useful when the inventory needs to be sorted based on quantity held in stock.
Learning goals: Implementing a
function
that is suitable to be used as the key
argument
for the sort method.

Function Specification: select_quantity
  • Parameters
    :
    • Tuple
      that contains a product code and quantity in stock for that product
  • Returns
    :
    • Quantity in stock (integer)
The function needs to use
subscription
to return the second
item
from a tuple.
Although the function is intended for a specific purpose, deriving
comparison values
, there isn't anything special about it. The only limitations are that it has to have exactly one parameter and return value.

Testing:
You can use following tuple to test your function
product = ("d0nk3y", 12)
When this tuple is given as an argument to the implemented function, it should return 12.
Warning: You have not logged in. You cannot answer.
The organize function itself follows a pretty familiar pattern where we first ask the user which field they want to sort by, and then use a
conditional structure
to choose the code that executes it:
def organize(collection):
    print("Choose a field to use for sorting the collection by inputting the corresponding number")
    print("1 - artist")
    print("2 - album title")
    print("3 - number of tracks")
    print("4 - album length")
    print("5 - release year")
    field = input("Choose field  (1-5): ")
    if field == "1":
        collection.sort(key=select_artist)
    elif field == "2":
        collection.sort(key=select_title)
    elif field == "3":
        collection.sort(key=select_no_tracks)
    elif field == "4":
        collection.sort(key=select_length)
    elif field == "5":
        collection.sort(key=select_year)
    else:
        print("Field doesn't exist")
Since we had the foresight to use integer as the type for the number of tracks field, they already get sorted correctly. However, trying to sort by length gives a bit problematic results:
 1. Mono, You Are There, 6, 1:00:01, 2006
 2. Slipknot, Iowa, 14, 1:06:24, 2001
 3. Panopticon, Roads to the North, 8, 1:11:07, 2014
 4. Canaan, A Calling to Weakness, 17, 1:11:17, 2002
 5. Funeralium, Deceived Idealism, 6, 1:28:22, 2013
 6. Alcest, Kodama, 6, 42:15, 2016
 7. Wolves in the Throne Room, Thrice Woven, 5, 42:19, 2017
 8. IU, Modern Times, 13, 47:14, 2013
 9. Deftones, Gore, 11, 48:13, 2016
10. PassCode, Clarity, 13, 49:27, 2019
11. Scandal, Hello World, 13, 53:22, 2014
While the order is mostly from shortest to longest, any albums over an hour long are considered shorter than the ones under an hour by the sort
method
. This is a problem that has been visited before: albums over an hour start with the "1" character which is smaller than any other numbers - except zero. For sorting purposes it would make more sense if all lengths included hours even when they'd be zero. For the exact same reason programmers like dates written as year-month-day - as it happens, they sort correctly by default as long as all numbers have leading zeros (e.g. 2015-07-22).
The first step in solving the problem is to add the zero hours into the collection dictionary. At this point we just write them in manually.
    collection = [
        {
            "artist": "Alcest",
            "album": "Kodama",
            "no_tracks": 6,
            "length": "0:42:15",
            "year": 2016
        },
        {
            "artist": "Canaan",
            "album": "A Calling to Weakness",
            "no_tracks": 17,
            "length": "1:11:17",
            "year": 2002
        },
        {
            "artist": "Deftones",
            "album": "Gore",
            "no_tracks": 11,
            "length": "0:48:13",
            "year": 2016
        },
        # rest is cut, the code example itself defines 8 more
    ]
This by itself doesn't guarantee anything though. The user can still
input
lengths without hours in them. In general it should be the code that fixes issues like this, not the user. Conveniently, we already have a
function
for prompting the length - it just doesn't do a whole lot yet. Since it exists, we can just add a couple of things:
  1. Checking that the input is valid
  2. Adding zero hours if needed
This can be by done splitting the user's input by colons and examining each part individually. We are going to make a relatively sane assumption that all albums are less than 10 hours long. This means one zero is sufficient for hours, and albums longer than an hour don't need leading zeros.
def prompt_time(prompt):
    while True:
        parts = input(prompt).split(":")
        if len(parts) == 3:
            h, min, s = parts
        elif len(parts) == 2:
            min, s = parts
            h = "0"
        else:
            print("Input the time as hours:minutes:seconds or minutes:seconds")
            continue

        try:
            h = int(h)
            min = int(min)
            s = int(s)
        except ValueError:
            print("Times must be integers")
            continue

        if not (0 <= min <= 59):
            print("Minutes must be between 0 and 59")
            continue
        if not (0 <= s <= 59):
            print("Seconds must be between 0 and 59")
            continue
        if h < 0:
            print("Hours must be a positive integer")
            continue

        return f"{h}:{min:02}:{s:02}"
Well, that wasn't so simple. The function became a bit long because we have to check each part individually: check that they are numbers, and are within the valid range.
We've also snuck a new
keyword
, continue, into this example. Whereas
break
interrupts the execution of a
loop
, continue interrupts the current
iteration
and skips to the next one. In this example it means that as soon as we hit a check that fails, the code jumps to prompt for a new input. We've used continue here because otherwise all of these checks would have to be nested, and it would look rather unpleasant. Here's an animation that illustrates how continue works:
Note also how we've placed return at the end of the
while loop
. When the code gets an input that passes all checks it can be
returned
, and exit the loop entirely.
Generally speaking,
continue
is not used particularly often in
loops
. It's only really needed in situations like this where the code makes multiple checkes, each of which can cause skipping to the next iteration - whether it's prompting for the next input in a
while
loop, or moving on to the next
item
in a
for
loop. A continue can always be replaced by nested
conditional structures
. It's just a useful tool that can sometimes lead to prettier code than the alternative.
After all these changes, the user can now add albums that are shorter than an hour, and sorting by length works correctly.
This program manages an album collection. You can use the following features:
(A)dd new albums
(R)emove albums
(S)how the collection
(O)rganize the collection
(Q)uit
Make your choice: a  
Fill the information for a new album. Leave album title empty to stop.
Album name: Rotten Tongues
Artist name: Curse Upon a Prayer
Number of tracks: 9
Total length: 43:17
Release year: 2015
Album added
Album name: 
Make your choice: o
Choose a field to use for sorting the collection by inputting the corresponding number
1 - artist
2 - album title
3 - number of tracks
4 - album length
5 - release year
Choose field  (1-5): 4
Make your choice: s
 1. Alcest, Kodama, 6, 0:42:15, 2016
 2. Wolves in the Throne Room, Thrice Woven, 5, 0:42:19, 2017
 3. Curse Upon a Prayer, Rotten Tongues, 9, 0:43:17, 2015
 4. IU, Modern Times, 13, 0:47:14, 2013
 5. Deftones, Gore, 11, 0:48:13, 2016
 6. PassCode, Clarity, 13, 0:49:27, 2019
 7. Scandal, Hello World, 13, 0:53:22, 2014
 8. Mono, You Are There, 6, 1:00:01, 2006
 9. Slipknot, Iowa, 14, 1:06:24, 2001
10. Panopticon, Roads to the North, 8, 1:11:07, 2014
11. Canaan, A Calling to Weakness, 17, 1:11:17, 2002
12. Funeralium, Deceived Idealism, 6, 1:28:22, 2013
This example also shows that zero hours are correctly added.
The last sorting feature we're going to implement before moving on is the ability to choose ascending or descending order. This can be achieved with the other
optional argument
of the sort
method
, reverse, which has the
default value
of False. If we want we can change it to True which reverses the order (from ascending to descending). All we need to do is to add a prompt about the order:
def organize(collection):
    print("Choose a field to use for sorting the collection by inputting the corresponding number")
    print("1 - artist")
    print("2 - album title")
    print("3 - number of tracks")
    print("4 - album length")
    print("5 - release year")
    field = input("Choose field  (1-5): ")
    order = input("Order; (a)scending or (d)escending: ").lower()
    if order == "d":
        reverse = True
    else:
        reverse = False
    if field == "1":
        collection.sort(key=select_artist, reverse=reverse)
    elif field == "2":
        collection.sort(key=select_title, reverse=reverse)
    elif field == "3":
        collection.sort(key=select_no_tracks, reverse=reverse)
    elif field == "4":
        collection.sort(key=select_length, reverse=reverse)
    elif field == "5":
        collection.sort(key=select_year, reverse=reverse)
    else:
        print("Field doesn't exist")
So we prompt for another
input
and make the ordering choice based on that. This is done by setting the reverse
variable
to either True or False. In this case we've chosen that any input that is not l or L will set the order to ascending because it's the default.

Inventory Arrangement

As we just learned, the ordering created by the sort method can be affected by using its optional arguments. This task continues from the previous one: you are now going to use the function you defined there to sort an inventory.
Learning goals: Using a custom
function
when sorting a
list
with the sort
method
.
Introduction:
Use the code file from the previous exercise as a template. Change the
main program
to this:
inventory = [("donkey", 12), ("Moomin mug", 1), ("poleax", 4)]
# write a line that sorts the inventory by quantity in descending order
print(inventory)
Answer Specification:
The answer is a line of code that was written in place of the comment in the above main program. When the program is ran it should give the following result, where the item with the highest quantity is first, and the one with the lowest is last:
[('donkey', 12), ('poleax', 4), ('Moomin mug', 1)]
Type the code that sorts the list as described.
Warning: You have not logged in. You cannot answer.

Economizing Printouts

The last task in this material is to show how list slicing can be used in limiting how much is printed. If the collection grows to substantial size, browsing the output can become quite an ordeal. We're going to implement a rudimentary solution that shows 20 results at a time, whenever the user presses enter. We'll also do some final touch-ups to the output.
Learning goals: This section should give you some idea about how list slicing is used. We're also going to show you a special type of for loop that is used for repeating the code a certain number of times.

Paginated Lists

Our goal is to print 20 items from the collection at a time, and wait until the user presses enter before printing the next 20. Let's start with the easiest part, which is figuring out how to get the first 20
items
from a
list
. In order to keep the first example concise we're going to use a smaller number and a shorter list - time for the animals list to make comeback. We'll take the first three animals:
In [1]: animals = ["walrus", "duck", "donkey", "llama", "koala", "dromedary", "moose"]
In [2]: top3 = animals[:3]
In [3]: top3
Out[3]: ['walrus', 'duck', 'donkey']
The new thing is on the second line. The [:3] notation indicates
slicing
from beginning of the list until the
index
3. The first index to be included in the slice is placed on the left side of the colon. If it's not there, 0 is used. On the right is the first index that will not be included in the slice. If it's not given, everything until the end of the list is included. We would get the same result if the slice was written as [0:3].
Slicing is nice in the sense that it doesn't complain about going outside the list:
In [4]: animals[10:15]
Out[4]: []
Conveniently this example also shows how to write a slice that doesn't begin at the start of the list. Slicing can be used to make the show function print only first 20 albums from the collection:
def show(collection):
    for i, album in enumerate(collection[:20]):
        print(
            f"{i + 1:2}. "
            f"{album['artist']}, {album['album']}, {album['no_tracks']}, "
            f"{album['length']}, {album['year']}"
        )

Border Control

'One common scenario with lists is a situation where one or both ends of the list have items that should not be processed. For instance, data from a table can have a header row, or a 2-dimensional list of a game board can have borders. In Python the end indices are often best handled with negative indices because then we don't need to care about list length.
Learning goals:
List
slicing
and negative
indices
.

Introduction:
As an example we can take one row from a game's field as a list where numbers 0 to 9 are symbols relevant to the game, and 10 is border. The list can be defined as:
In [1]: row = [10, 0, 1, 1, 1, 0, 1, 2, 2, 1, 10]

Answer Specification:
The answer is a line of code that prints everything from the row variable except the
items
at both ends. The most convenient way is to use list slicing - write a print statement that uses slicing. You should use negative indices for leaving the last item out of the slice. In fact, the checking expects negative indices - don't bother counting what the last index is. When using negative indices, the last item is always -1, the second to last -2 etc.
Write the list slicing below.
Warning: You have not logged in. You cannot answer.

Numbers in a Range

In order to print the next 20
items
we need two things:
  1. We have to find out how many 20 item prints have to be done.
  2. We need to make a
    loop
    that gets as many iterations.
Let's start with the first problem. A list's length can be found out with the len function. After that it's a matter of simple division to figure out how many 20 item chunks are in there. The only problem is rounding. If there's exactly 20 albums, one print is sufficient but if there's 21, two prints are required. The math module has a ceil function that solves the problem rather neatly:
def show(collection):
    pages = math.ceil(len(collection) / 20)
The result of this calculation can be used in declaring the new printing loop. The
loop
needs to have a certain number of
iterations
, and on each iteration, 20 albums are printed. A loop that's executed a definite number of times is often implemented with a specific type of
for loop
. In this loop, the right hand operand of the in operator is not an existing
list
. Instead, it's a range object that's been spefically created for the purpose. It's an
object
that produces a desired range of numbers:
In [1]: numbers = range(10)
In [2]: for number in numbers:
   ...:     print(number)
   ...:
0
1
2
3
4
5
6
7
8
9
If we go through numbers [0, ..., 9], it naturally leads to 10 iterations. The range object can be put directly on the loop declaration, and usually is:
In [1]: for number in range(10):
   ...:     print(number)
   ...:
0
1
2
3
4
5
6
7
8
9
The
argument
to range can of course be a
variable
instead of a
literal value
. When we apply this knowledge, the new show function is starting to shape up:
PER_PAGE = 20

# other function definitions have been cut

def show(collection):
    pages = math.ceil(len(collection) / PER_PAGE)
    for i in range(pages):
        start = i * PER_PAGE
        end = (i + 1) * PER_PAGE
        format_page(collection[start:end])
The core idea of this code is to print a new
slice
from the
list
by starting from
iteration
index times 20 (the first index is 0) and ending to iteration index + 1 times 20. This produces slices 0:20, 20:40, 40:60 etc. We assigned the number 20 to a
constant
to make the code easier to modify later. As for the format_page
function
that is
called
in this example, it's actually just a copy of what the show function used to be. Just with a more accurate name for the
parameter
.
def format_page(lines):
    for i, album in enumerate(lines):
        print(
            f"{i + 1:2}. "
            f"{album['artist']}, {album['album']}, {album['no_tracks']}, "
            f"{album['length']}, {album['year']}"
        )
This is all great. The result just isn't any different from before because printing doesn't actually stop after each chunk of 20. Because the input function pauses program execution until the user gives their input, we can use it in a clever way to solve this problem.
def show(collection):
    pages = math.ceil(len(collection) / PER_PAGE)
    for i in range(pages):
        start = i * PER_PAGE
        end = (i + 1) * PER_PAGE
        format_page(collection[start:end])
        if i < pages - 1:
            input("   -- press enter to continue --")
As a small detail, the
if statement
before the input is used to skip the prompt when the last page is printed. The example below shows how this code works, but we changed the PER_PAGE
constant
to 5 because we don't actually have over 20 albums in the collection currently.
This program manages an album collection. You can use the following features:
(A)dd new albums
(R)emove albums
(S)how the collection
(O)rganize the collection
(Q)uit
Make your choice: s
 1. Alcest, Kodama, 6, 0:42:15, 2016
 2. Canaan, A Calling to Weakness, 17, 1:11:17, 2002
 3. Deftones, Gore, 11, 0:48:13, 2016
 4. Funeralium, Deceived Idealism, 6, 1:28:22, 2013
 5. IU, Modern Times, 13, 47:14, 2013
   -- press enter to continue --
 1. Mono, You Are There, 6, 1:00:01, 2006
 2. Panopticon, Roads to the North, 8, 1:11:07, 2014
 3. PassCode, Clarity, 13, 49:27, 2019
 4. Scandal, Hello World, 13, 53:22, 2014
 5. Slipknot, Iowa, 14, 1:06:24, 2001
   -- press enter to continue --
 1. Wolves in the Throne Room, Thrice Woven, 5, 42:19, 2017

Headstart

Defining the number of iterations of a for loop with range is common, but it can also be used to implement loops where a certain series of numbers is required for calculations. In some of these cases starting from zero is not desired (imagine for instance using the loop variable as a divisor). This task is about producing a series of numbers using range.
Learning goals: Generating series of numbers with the range
function
. Using range in
loops
.

Introduction:
For reasons that have absolutely nothing to do with a later exercise we want a loop where the
loop variable
is used as a divisor. This means starting from zero is generally not very good. The framework for this exercise is something like this:
In [1]: dividend = 27
In [2]: # your loop declaration goes here
   ...:    print(dividend / divisor)
   ...:

Answer Specification:
The answer we're looking is the
for loop
declaration that fits into the above example. We'll say that the divisor variable should get values from 2 to 12 (inclusive). You'll need a suitable range
function call
for your loop.
Write a for-loop definition, that goes through these numbers using the range-function. You choose the loop variable name yourself.
Warning: You have not logged in. You cannot answer.
That went pretty well, at least if we ignore the fact that our numbering starts from 1 on every "page". In order to solve this problem we need to smuggle a second
argument
to the format_page function: the page number.
def format_page(lines, page_n):
    for i, album in enumerate(lines):
        print(
            f"{i + 1:2}. "
            f"{album['artist']}, {album['album']}, {album['no_tracks']}, "
            f"{album['length']}, {album['year']}"
        )
Just to show you some new things, there's another perfectly valid place for the index math in this function. It turns out that enumerate accepts a second argument as well, one that can be used to change the starting number from zero to something else:
def format_page(lines, page_n):
    for i, album in enumerate(lines, page_n * PER_PAGE + 1):
        print(
            f"{i + 1:2}. "
            f"{album['artist']}, {album['album']}, {album['no_tracks']}, "
            f"{album['length']}, {album['year']}"
        )
In this example the change doesn't really matter, but if the ordinal was used more than once inside the loop, the advantages would be way more apparent. All that's left is to hand a value to this new parameter from the show function:
def show(collection):
    pages = math.ceil(len(collection) / PER_PAGE)
    for i in range(pages):
        start = i * PER_PAGE
        end = (i + 1) * PER_PAGE
        format_page(collection[start:end], i)
        if i < pages - 1:
            input("   -- press enter to continue --")
There's one thing we didn't really make a number about because it should be obvious by now but... Did you notice how we used the same variable i in both functions? This does not give us any trouble because, once again, these are separate variables in separate
scopes
. Just a reminder in case you've forgotten one of the advantages of using functions.
Now the result is what we wanted:
 1. Alcest, Kodama, 6, 0:42:15, 2016
 2. Canaan, A Calling to Weakness, 17, 1:11:17, 2002
 3. Deftones, Gore, 11, 0:48:13, 2016
 4. Funeralium, Deceived Idealism, 6, 1:28:22, 2013
   -- press enter to continue --
 5. IU, Modern Times, 13, 47:14, 2013
 6. Mono, You Are There, 6, 1:00:01, 2006
 7. Panopticon, Roads to the North, 8, 1:11:07, 2014
 8. PassCode, Clarity, 13, 49:27, 2019
 9. Scandal, Hello World, 13, 53:22, 2014
10. Slipknot, Iowa, 14, 1:06:24, 2001
   -- press enter to continue --
11. Wolves in the Throne Room, Thrice Woven, 5, 42:19, 2017

Finishing Touches

The prints are admittedly still a bit unseemly, and zero hours are visible. Let's close this chapter by modifying the new format_page function. All the changes are applied to the
f string
:
def format_page(lines, page_no):
    for i, album in enumerate(lines, page_no * PER_PAGE + 1):
        print(
            f"{i:2}. "
            f"{album['artist']} - {album['album']} ({album['year']}) "
            f"[{album['no_tracks']}] [{album['length'].lstrip('0:')}]"
        )
The formatting template has been rewritten and
keyword arguments
make a comeback. The lstrip used for length removes zero hours from length if it finds them, and actually also removes zero minutes if the album is very short (you should examine how strip works very carefully!). The result is almost beautiful:
 1. Alcest - Kodama (2016) [6] [42:15]
 2. Canaan - A Calling to Weakness (2002) [17] [1:11:17]
 3. Deftones - Gore (2016) [11] [48:13]
 4. Funeralium - Deceived Idealism (2013) [6] [1:28:22]
 5. IU - Modern Times (2013) [13] [47:14]
   -- press enter to continue --
 6. Mono - You Are There (2006) [6] [1:00:01]
 7. Panopticon - Roads to the North (2014) [8] [1:11:07]
 8. PassCode - Clarity (2019) [13] [49:27]
 9. Scandal - Hello World (2014) [13] [53:22]
10. Slipknot - Iowa (2001) [14] [1:06:24]
   -- press enter to continue --
11. Wolves in the Throne Room - Thrice Woven (2017) [5] [42:19]
That said, the code itself might not look that neat anymore. The placeholders inside the string are starting to look very busy. In this scenario it might be worth considering whether the old
format method
might provide a cleaner solution. The biggest diference with these two approaches is that while
f strings
grab the values for placeholders from the program's
namespace
, the format method takes those values from the arguments given to it. The example below might have more lines of code, but the string itself looks a lot cleaner:
def format_page(lines, page_no):
    for i, album in enumerate(lines, page_no * PER_PAGE + 1):
        print("{i:2}. {artist} - {album} ({year}) [{tracks}] [{length}]".format(
            i=i,
            artist=album["artist"],
            album=album["album"],
            tracks=album["no_tracks"],
            length=album["length"].lstrip("0:"),
            year=album["year"]
        ))

In the Next Episode...

In the thrilling season closer of this programming drama we'll perform a couple more tricks with lists: removing items and changing their values. Frankly those just didn't fit in this time, there's no other reason. We'll also learn how to actually save the collection when the program is closed which sounds extremely useful for anyone who isn't prepared to have the program open indefinitely.
Oh, there's also the small detail of giving an introduction to graphical user interfaces in the final episode...

Closing Words

Together with
lists
,
loops
form a toolkit that, when combined with what we previously learned, can theoretically be used to implement almost anything. Python's lists in particular are extremely useful. The more you program with Python, the more you will notice how the solution you're looking for is a list. Loops often go hand in hand with lists because they're the only reasonable way to go through values inside lists.
The advantage of splitting code to
functions
should have also become more apparent in this material. Things like universally usable prompt functions make the implementation of core features much more effortless as does putting all prints into their own functions. Likewise the splitting of features into functions made more sense since they were doing completely different things.
In general program design became increasingly important in this material. We even noticed that our current solution could have been implemented better. This happens rather often regardless of how experienced the programmer is or how many iterations they've made of the same programs already.
When the toolkit expands, the most important programming skill is ultimately the ability to work systematically. If you "just start from somewhere" without thinking about the other parts at all, you may find yourself absolutely swamped with no way out. What you learned from this material is already a solid basis for taking a systematic approach to implementing your own course project, and the exercises will give you another big boost.

Image Sources

  1. original license: CC-BY-NC 2.0 (caption added)
  2. original license: CC-BY 2.0 (caption added)
  3. original license: CC-BY 2.0 (caption added)
  4. original license: CC-BY-SA 2.0
  5. original license: CC-BY-NC 2.0 (caption added)
  6. original license: CC-BY-NC-SA 2.0
  7. original license: CC-BY 2.0 (caption added)
  8. original license: CC-BY 2.0 (caption added)
?
  1. Description
  2. Examples
Absolute path is an operating system term that refers to the full "address" of a file or folder. Absolute path is written starting from the disk root. When absolute path is used, the current directory does not matter. Absolute paths are usually avoided in code - especially in applications that are meant to be shared. Another user is very unlikely to have the exact same folder structure as the application's developer. In particular if an absolute path refers to the user's home folder, it is very likely not going to be the same for another user.
Ajonaikaisesta (engl. run time) puhuttaessa määreenä on se aikaväli, kun ohjelma on käynnissä. Esimerkiksi Pythonissa virheet (syntaksivirheitä lukuun ottamatta) tarkastetaan ajonaikaisesti. Ohjelma saattaa siis olla käynnissä ja toimia tiettyyn pisteeseen saakka, kunnes törmätään käsittelemättömään poikkeukseen – ajonaikaiseen virheeseen (engl. run time error).
  1. Description
  2. Esimerkit
Alustamisella (engl. initialize) tarkoitetaan yleisesti jonkin arvon asettamista muuttujalle muuttujan luonnin yhteydessä. Pythonissa ei ole mahdollista luoda muuttujaa, jolla ei ole myös jotain arvoa. Niinpä tyypillisesti käytetäänkin sanamuotoa ”muuttuja alustetaan arvolla x”, millä tarkoitetaan sitä, että muuttuja, joka luodaan, saa luomisen yhteydessä (eikä vasta joskus myöhemmin) arvon x.
  1. Description
  2. Esimerkit
Argumentti (engl. argument) on funktiokutsussa käytettävä arvo, joka välitetään kutsuttavalle funktiolle. Funktiokutsun alkaessa argumentit sijoitetaan parametreiksi kutsuttuihin muuttujiin, joiden kautta arvoihin pääsee funktion sisällä käsiksi.
Arvo (engl. value) on konkreettista, tietokoneen muistissa sijaitsevaa tietoa, jota käytetään ohjelman suorituksen aikana. Arvoilla on tyyppi ja sisältö; esimerkiksi numero 5 on tyypiltään kokonaisluku, jonka sisältö on 5. Useimmiten arvot liitetään muuttujiin, mutta myös operaatioiden ja funktiokutsujen paluuarvot sekä koodissa sellaisenaan esiintyvät arvot ovat arvoja. Käytännössä siis kaikkea konkreettista mitä ohjelma käsittelee voidaan kutsua arvoiksi.
Assignment is related to variables and values. A typical figure of speech is "assigning to a variable" which means giving a certain value to a variable (e.g. x = 5). More specifically, in Python, assignment to a variable means creating a connection between the name and value of the variable - the variable is a way to find the value.
Similar expressions that can be used to mean the same thing are: "saving to a variable", "storing to a variable", "referring to a variable", "stuffing a value into a variable"... etc.
Assignment operator i.e. the = character is used for variable assignment. When using the operator, the target variable must always be on the left side and the value (or statement that produces the value) on the right side.
Attribute is a value that belong to an object, sometimes also called property. It's a name that belongs to the object's internal namespace and it can be accessed through the object: timestamp.tm_hour would read the hours from a timestamp.
  1. Description
  2. Kurssin avainsanat
Avainsanat (engl. keyword) ovat ohjelmointikielessä kielen käyttöön varattuja sanoja, joilla on erityinen merkitys. Hyvät tekstieditorit tyypillisesti merkitsevät avainsanat muista nimistä eroavalla tavalla (esimerkiksi lihavoinnilla tai tietyllä värillä). Avainsanat ovat yleensä suojattuja, eli samannimisiä muuttujia ei voi luoda. Yleisiä avainsanoja Pythonissa ovat esimerkiksi funktioihin liittyvät def ja return. Avainsanat ovat siis osa ohjelmointikielen kielioppia.
Boolean is the most simple data type in programming languages because it has only two values: true (True in Python) and false (False in Python). Things like comparison operators return booleans, and they are often used in conditional statements and while loops. In Python all values are equivalent to one of the boolean values. Generally all so called empty values (0, "", None etc.) are equal to False while the rest are equal to True.
  1. Description
  2. Extra info
Boolean operator refers to Boolean algebra which deals in values of truthfulness. These operations include and, not, and or - all familiar from conditional statements. Out of these and is True if and only if both operands are True; or is True if at least one operand is True; and not is True is its sole operand is False.
Branch is an execution path in the program that is mutually exclusive with other branches in the same control structure. For example in a conditional structure each if, elif and else define their own branches and only of them is executed.
Bug is an error in the program's source code. As the result of a bug the program either doesn't start at all, crashes during execution, doesn't work correctly in some situations, or can even cause severe security issues. Careful programming and testing - including rare edge cases - reduces the probability of bugs. Tracking down the part of code that causes a bug and fixing it is called debugging.
Buitin functions are function that are included in the Python core. They can always be used without importing any modules or libraries.
Callback is a common mechanism, especially in modern programming, where another part of the program - often made by someone else - is given a function it is to call during its execution. If a normal function call is like a phone call, a callback is a like a call request. If a part of the program uses a callback, it usually described what kind of a function it accepts - especially what parameters the function can/must have and what kind of a value it should return.
Where UNIX-based systems produce \n characters (newline) to indicate line breaks, Windows uses \r\n where the r is a carriage return character. It's a remnant from mechanical typewriters, and indicates the procedure of physically moving the typewriter head to the beginning of the line. In general this is just something that's good to know - Python treats both line breaks quite nicely.
Code block or block is a term used for liens of codes that belong to the same context. A block is formed of lines that have the same indentation level (although a block can also contain other blocks). Typical blocks are the executable parts of conditional structures i.e. the indented code lines that follow a condition. A block ends when a line with less indentation than ones belonging to the block is encountered.
Code file is a text file that contains executable code. A Python code file can be ran from the terminal by typing python code.py where code.py is the file's name. When you run a code file the return values of individual lines are not shown unless they have been specfically rpinted.
  1. Description
  2. Material example
  3. Basic use
Command line argument or parameter is a name used for additional information that is passed to a terminal program when it's started. Command line arguments are typically separated by spaces. E.g. in python code.py, code.py is actually a command line argument. Command line arguments can be accessed in Python from the sys module's argv variable.
Comparison operators are used for comparing values to one another. They are familiar from mathematics and can be used to compare size. Comparison operators return a boolean value, True or False, depending on the result of the comparison. Comparison operators are: <, <=, >, >=, == and !=
Comparison values are used e.g. in sorting lists. A comparison value is a value derived from a list item that is used instead of the item itself in sorting. For instance, if a list contains lists, a comparison value can be an item taken from a certain index of each inner list. It can also be a more complex derivative such as the sum of items or their mean value.
  1. Description
  2. Examples
Condition is used in this course to refer to the part of conditional statements and while loops that defines when the statement is true. Anything between the keyword that starts the stamement and the colon that ends it is basically its condition.
  1. Description
  2. Examples
Conditional statement is a line of code that defines a single condition, followed by an indented code block which defines what should be done if the condition is true. Conditional statements include if and elif statements, the latter of which cannot be present without the former. Conditional statements that are linked together form conditional structures. A conditional statement must always end with a colon and it must be followed with at least one indented code line.
  1. Description
  2. Examples
Conditional structure is a structure that consists of one or more conditional statements that branches program execution. Most of them have at least two branches: if and else. Between the two there can also be an indefinite number of branches under elif statements. It is also possible to have nothing but a single if statement in a structure. Each branch in a conditional structure has at least some code that defines what the program does in a situation falling under a condition.
As a whole a conditional structure is interpreted by checking the truthfulness of the first branch (if). If it evaluates to True, program execution continues to the code block inside the statement after which execution skips the rest of the structure. If it evaluates to False, other branches will be evaluated in sequence until one of them is True, or if none of them are, the else branch is executed.
  1. Description
  2. Examples
Constant is a named literal value. They are used especially when the same literal value is used repeatedly in a program. Named constants are also just in general more practical in code than seemingly arbitrary literal values because its meaning can be derived from its name. Likewise if the value needs to be changed it is much easier if you only need to change it in one place (where it's defined). Python doesn't actually have a way to define "real" constants - they are simply variables. The difference is implied by writing constant names in full upper case. E.g THE_ANSWER = 42.
Control structure is a common name for different programming structures that control the program flow in some way. Within this course this includes conditional structures, loops and exception handling.
Data (engl. data) on ohjelmoinnin asiayhteydessä mitä vaan tietoa, joka ei kuitenkaan yleisesti kata itse ohjelmakoodia. Yleensä datasta puhuttaessa tarkoitetaan yksittäisiä literaaliarvoja, muuttujien sisältämää tietoa tai jostain tietolähteestä (kuten tiedostosta tai verkko-osoitteesta) luettua tai sinne kirjoitettua tietoa. Nyrkkisääntönä voi kuitenkin pitää sitä, että koodi ja data ovat eri asioita, ja koodi käsittelee dataa. (Joissain yhteyksissä koodikin lasketaan dataksi, mutta näihin ei tällä kurssilla syvennytä.)
Data format is the "syntax" of a data file, and it defines how data has been saved to the file. Data format also defines what kind of data can be stored in the file. The basic idea of each data format is to enable the saving of data structures in a program in some format that also makes it possible to load them back in later. A data format can be based on some existing standard (e.g. JSON) but ultimately it's the programmer's responsibility to choose what data is relevant for the program and how to best represent it.
Data structure is a common name for collections that contain multiple values. The purpose of a data structure is to store data that consists of more than one value. There are various ways to make a data structure and each of them convenient means for adding, removing and modifying values. Data structures implement a way to bundle data together. Generally the difficult details involved have been hidden from the programmer.
Choosing data structures that serve the purposes of your program and are easy to handle in your code is essential. The most common structures in Python are list, tuple and dictionary. Another convenient structure is set which doesn't contain duplicate values. In addition to built-in structures, more can be found from the collections module.
On later courses you'll also become familiar with other important structures like trees and graphs.
Debugging is the process of hunting down and fixing programming errors i.e. bugs. There are many ways to track down bugs. One of the more common ones in Python is the error message it shows when a program crashes. Another common method to find errors is the use of debug prints. This means putting additional print function calls in the code temporarily to either see how far the code gets or what kinds of values variables have. Debugging is such an important part of programming that there are even specific debugging tools that have been developed. We don't use them on this course however.
Default value is a value that can be defined for a function parameter. It will be used for that parameter's value if its corresponding argument has not been given in a function call. E.g. in def prompt_length(question, maximum=10): function definition, the maximum parameter has been made optional by giving it the default value of 10.
  1. Description
  2. Definition
  3. Value lookup
  4. Modifying dictionaries
Dictionary is a data structure that assigns keys (usually strings) to its values. The advantage of using dictionaries is that descriptively named keys make code that handles the data structure much easier to read. Starting from Python 3.7 dictionary keys and values are guaranteed to be in the order they were added.
In Python docstring is a comment-like entity but it has a special meaning. A docstring is usually delimited with triple quotes (i.e. '''document''' or """document""". If a docstring is placed immediately below a function's def statement (indented!), it becomes the function's documentation that is shown with the help function. Likewise a docstring placed at the very beginning of a code file becomes the module's documentation. A good doctstring describes what a function does, and explains its parameters and return values.
Docstrings should not be used as comments! Outside of the aforementioned places, commenting should be done with actual comments (lines starting with #).
Epätosi (engl. false) on toinen kahdesta mahdollisesta totuusarvosta ja toisen, eli toden, vastakohta. Sitä voidaan pitää lopputuloksena loogisissa ja vertailuoperaatorioissa, jotka eivät pidä paikkansa. Esimerkiksi vertailuoperaatio 5 < 4 ei pidä paikkansa, joten kyseinen operaatio evaluoituu epätodeksi. Pythonissa epätotta merkitään avainsanalla False.
  1. Description
  2. Examples
Error message is the Python interpreter's way of informing about an exception in a program. The error message contains information about where in the program the exception happened, which line caused the exception, the exception's type (e.g. SyntaxError) and a short verbal description. Error messages are your best friends and reading them is a very integral programming skill. Don't be afraid of them, they are only there to help you find out what's wrong in the code!
Escape in programming terms means interpreting a character in an exceptional way. For instance "n" is just the letter n but "\n" is a newline character. In this example the backslash character \ causes the normal interpretation of the n character to be escaped and replaced by another interpretation. The backslash functions as an escape character. One typical use is including " in a string that's delimited with ": "donkey ear interval is 14\""
Evaluointi (engl. evaluation) tarkoittaa lausekkeen tai muuttujan arvon lopputuloksen määrittämistä. Suoritettaessa lauseet evaluoituvat joksikin tietyksi arvoksi.
Event is a programming cocept that is generally used in the context of interactive applications that run in real time. These applications usually have a main loop that monitors for events. Events include: user clicks with the mouse, user presses a key, a certain amount of time has passed etc. Handler functions can be attached to events, and they will be called whenever the event is detected. This makes programming of interactive programs much easier because there's no need to worry about how actions on the screen are detected when implementing the application itself.
  1. Description
  2. Examples
Exception is a scenario in programming where the program cannot proceed as instructed. Exceptions have a type (e.g. TypeError) that can be used in handling the exception within the program. Type can also be useful when trying to solve the issue if it is not intended. In most cases exceptions also come with a message that gives more details about what caused the issue. In Python exceptions are handled with try-except structures.
Exception is the base class of most common exceptions. We also call it the Pokémon exception because if you use it in a try-except structure it will catch all the exceptions. In most cases this is not a good thing. It makes interpreting problem situations more difficult for both the user, and you, the developer. The latter is due to the fact that it will also catch any mistakes you made in your code, and you won't get any useful information when the program isn't behaving correctly.
Execution or running means going through a program or code snippet so that the instructions written within are carried out by the computer. Python interpreter executes code one statement at a time. While this is ongoing the program is "running". Execution ends when there is no more code to run, there's an unrecoverable error or when the program ends itself.
File extension is the part of the file's name that is on the right side of the last period in the name. They are commonly used for indicating file types. Image files for instance often have .png or .jpg as their extension. Python code files usually have .py at the end (e.g. donkeyswings.py).
File handle is a special object that Python uses to refer to an opened file. Most important note is that the handle is not the same as the file's contents - the handle can be used to read the contents, or write to the file. A file handle is obtained with the open function with the file's location (path) and the opening as arguments. E.g. with open("donkey.txt", "r") as somefile: opens donkey.txt inside a with statement (where files usually should be opened), with somefile as the file handle.
Filename is the name of a file that consists of the file's actual name and a file extension. For instance, donkeyswings.py is a complete filename where the given name is donkeyswings and the extension is .py.
Inside code, filenames are always strings.
  1. Description
  2. Conversions
Floating point number or float is an approximation for decimal numbers used by computers. Computers can't handle real decimal numbers due to their architecture, and that leaves us with floats. Floats can occasionally cause rounding errors - something to keep in mind. Python has a module for handling decimal numbers more accurately, called decimal.
  1. Description
  2. Examples
  3. Choosing parameters
The format method of strings is a powerful way in Python to insert values of variables into text that is either printed or saved to a file. Formatting works by defining placeholders in strings (e.g. {:.2f}) for marking spots where the format method arguments will be placed. Example: "Interval between donkey's ears is {:.2f}".format(measurement).
Note: format is an older way for general string formatting. Using f strings is a more modern way. However, there are still uses for the good old format method too.
  1. Description
  2. Examples
Function is an independent part of a program that consists of the defining line (with the def statement) and the lines of code that defines the function's behavior. Functions are used to clarify program structure and to reduce redundancy. Functions communicate with each other and the main program through their parameters and return values. Variables (including parameters) defined inside a function cannot be accessed from outside the function. Likewise functions should not read values outside of their own scope.
  1. Description
  2. Examples
Function call is a procedure where the program's execution "jumps" to another location in the code - to the beginning of the function that is being called. When a function is called it is given a varying number of arguments - values that are assigned to parameters defined in corresponding positions in the function definition. A function's execution ends when a return statement is encountered or there are no more lines inside the function's code to execute. When this happens, the program's execution returns to the line where the function was called, and the function call itself is "replaced" by the function's return value.
In short function calls allow one part of the program to utilize another part - e.g. the main program can use a function, or a function can use another function.
  1. Description
  2. Examples
Functions are defined with the def statement which specifies the name of the function and the names its parameters. Choosing these is an essential part of writing generally useful functions. The name should describe what the function does accurately but shortly. Parameter names should be chosen so that it's easy to deduce what kinds of values they will take as arguments. The function's code is indented inside the def statement as its own block. A function code can - and often does - include multiple lines. It can also include further indentations (like control structures).
  1. Description
  2. Examples
Generator is a special type of object that works like a list in, for example, a for loop. However, it's not a series of values in memory like a list would be, but a special function that produces values in a lazy way, yielding a new one whenever it is called. Because of this it's not possible to show the "contents" of a generator, and it's not subscribable with indices. Generators are not included in beginner level courses.
  1. Description
  2. Esimerkit
  3. Tilasanakirjat
Globaali muuttuja (engl. global variable) on pääohjelman tasolla esitelty muuttuja, jota muokataan suoraan funktiossa tuomatta sitä funktion nimiavaruuteen parametrin kautta. Globaalien muuttujien käyttö on huonoa ohjelmointityyliä, ja niiden sijaan tietoa kuuluisikin kuljettaa funktioille argumentteina ja ottaa funktiolta vastaan paluuarvoina muutettuja arvoja. Näin tekemällä välttää niin kutsutun globaalin tilan, joka huonontaa koodin ymmärrettävyyttä.
Global scope encompasses all names (variables, functions etc.) that have been defined on the main program level. All names that belong to the global scope can be accessed from anywhere in the program code. However they can only be assigned new values in the main program level. In general functions should only use constants and other functions from the global scope. Main program variables should always be passed to functions through parameters.
A handler function is a function that has been connected to an event so that when the event occurs, the function is called. This often means that the handler is not called from within the same code file or module it was defined in, and instead it works as a callback. Handlers are often related to user interface and game libraries where the program's main loop is running inside the library and monitors events. In this scenario handlers are the actual application's means of implementing their functionality through events. Because the application's writer cannot influence how handlers are called, handler parameters and return values must match the requirements set by the library.
  1. Description
  2. Esimerkit
Hypystä (engl. jump) puhuttaessa tarkoitetaan ohjausrakenteen aiheuttamaa siirtymistä, jonka jälkeen ohjelman suoritus jatkuukin jostain muualta kuin seuraavalta koodiriviltä.
  1. Description
  2. Naming Conventions
Variables, functions, constants, modules and all kinds of things each have their own 'identifier - the part of the source code that's been assigned to mean that one particular thing. For instace if a programmer defines a variable width with the value 15 the name width can later be used to retrieve the variable's value. So the identifier can be thought of as a contract between the programmer and the Python interpreter about the meaning of a certain word in the code. Identifiers always belong to a namespace.
Indented code lines have blank characters in front of them, either spaces or tabs. The role of indentation in general is to organize code and improve its readability. However in Python indentation is also used as the syntax for separating code blocks from each other - all lines with the same indentation level belong to the same block. On this course we prefer spaces, and the width of one indentation level is 4 spaces. All reasonable text editors can be configured to insert spaces instead of the tab character when the tab key is pressed.
  1. Description
  2. Example
Index is an integer value that denotes the position of an item in an ordered collection (list, tuple, but also string!). Indices start from zero which makes the last index (collection length - 1). Index can also be thought of as distance from the beginning of the colection. Python supports negative indices where -1 points to the last item, -2 to second to last etc. Using an index to get an item from a collection is called subscription.
  1. Description
  2. Examples
When the index of a data structure, e.g. list, is used the act itself is called (index) subscription. The subscription is denoted with square braces, e.g. grades[0]. Subscription returns an item. Subscription outside the list causes an IndexError exception, and it's good to keep in mind that the last index of a list is its length - 1 (because indexing starts from zero). Index can also be negative - in this case counting starts from the end so that -1 is the last item of the list.
  1. Description
  2. Example
An infinite loop is a loop that does not have an end condition - the code inside it gets repeated "infinitely". Infinite loops do have uses in programming but they can also be caused unintentionally by a bug in the code. In Python infinite loops are usually "achieved" only by while loops.
  1. Description
  2. Examples
Input when used within the context of this course is a text-based command or answer to a question that's been requested from the program's user. It is prompted with the input function and will always be a string. When a program prompts for input the entire program stops until the user has given their input.
  1. Description
  2. Examples
Interface in general refers to a connection between two things, and in programming it particularly means the way in which two parts of a program are connected to each other. For instance we can talk about the interface of a function which refers to the way in which the function accepts information as parameters and returns information as its return value. Likewise libraries typically have an API (Application Programming Interface) that tells how the library's features are used. Humans are also connected to programs through interfaces, specifically user interfaces.
  1. Description
  2. Examples
Item or element is an individual value contained within a data structure. The term is most commonly used in the context of lists. In this context, items also have a position, index, that denotes its distance from the beginning of the list. Therefore the index of the first item in a list is 0.
Iteration is a concept related to loops. One iteration of a loop means executing the code inside the loop once.
  1. Description
  2. Examples
Key acts as an index for a dictionary. It can be used to look up a value from the dictionary. Each key corresponds to exactly one value. Keys are typically strings, but they can also be any immutable types like numbers or tuples.
  1. Description
  2. Examples
Keyword argument (kwarg) is used in function and method calls to assign arguments directly to parameter names. This is very often used with the format method: "Hello {name}".format(name="Hagrid"). Another common use case is with functions that have a whole lot of optional arguments and only some of them need to be given. Using keyword arguments can also make the code generally more readable, especially for arguments that are either True or False.
Kirjasto (engl. library) tai moduuli (engl. module) (kuten niitä Pythonissa virallisesti kutsutaan) on valmiiksi kirjoitettua koodia, jolla on oma rajattu tarkoituksensa. Tyypillisesti kirjasto sisältää ainakin nipun aihepiiriinsä kuuluvia funktioita, mutta voi sisältää muutakin (esim. luokkia tai vakioita). Esimerkiksi Turtle on kirjasto, jonka tarkoitus on tarjota helposti käytettäviä piirtofunktioita.
  1. Description
  2. Esimerkit
Kommentti (engl. comment) on kooditiedostossa olevaa tekstiä, joka ohitetaan kun koodia suoritetaan. Kussakin kielessä on oma tapansa sille miten rivi merkitään kommentiksi. Pythonissa se on #- eli risuaitamerkki (engl. hash character), jonka jälkeen riviltä löytyvän tekstin Python-tulkki ohittaa kokonaan. Kommenteilla voi selventää koodin lukijalle (tai itselleen) mitä koodissa tapahtuu. Yleensä kommentit on hyvä laittaa omille riveilleen kommentoitavan koodin yläpuolelle.
Ohjelman ja sen funktioiden toiminta kuvataan yleensä mieluiten dokumenttimerkkijonossa. Kommentteja käytetään enemmänkin välihuomioiden tekemiseen.
Toinen tapa käyttää kommentteja on tilapäisesti kommentoida rivejä pois esimerkiksi vaihtoehtoisen koodin testaamiseksi. Tällöin aiempaa koodia ei tarvitse poistaa – kätevää, jos myöhemmin osoittautuu, että sitä tarvitaan sittenkin.
Ohjelman käyttämät arvot ovat kovakoodattuja (engl. hard coded) silloin, kun ne esiintyvät literaaliarvoina – eli semmoisenaan – ohjelman lähdekoodissa sen sijaan, että ne selvitettäisiin ajonaikaisesti esimerkiksi kysymällä käyttäjältä tai lukemalla tiedostosta.
Käyttöliittymäelementti (engl. UI element, widget) on jokin (yleensä graafiselle) käyttöliittymälle ominainen komponentti, jonka kautta käyttäjän vuorovaikutus ohjelman kanssa on mahdollista. Tällaisia ovat esimerkiksi napit, valikot, liukusäätimet ynnä muut.
Lause (engl. statement) on ohjelmointikielessä nimitys yksittäiselle suoritettavalle asialle, joka on yleensä yksi koodirivi.
Lauseke (engl. expression) tarkoittaa ohjelmoinnissa evaluoitavaa yksikköä. Esimerkiksi 5 + 5 ja "aasi" != "apina" ovat lausekkeita, jotka evaluoituvat arvoiksi 10 ja True. Lauseke yksin ei muuta ohjelman tilaa mitenkään, ellei sillä ole sivuvaikutuksia. Sen sijaan lauseke vaikuttaa osana lausetta.
  1. Description
  2. Examples
List is an ordered collection of values, and in Python it's a true swiss army knife. A list can contain values of any types, and its size is not limited.
Values inside a list are called items or elements. Each item has its own designated spot inside the list, called index. Indices start from zero! In addition, list is a mutable type. The third material contains a lot of information about lists.
A list can also contain other lists. Such a construct can also be called a two-dimensional list. Of course it's possible to have more than two levels of nested lists, which increases the number of dimensions. These would be called multidimensional lists.
Literal (literal value) is a generic name for any values that are present in the code as such. I.e. the value is not assigned to a variable but has been written into the code itself. For instance in the statements x = 5 and print("donkey"), 5 and "donkey" respectively are literals. The term is used primarily for simple types: numbers, boolean values and strings.
Local variable is a variable that has been defined inside a limited scope, typically - and especially on this course - inside a function (including function parameters). A local variable cannot be accessed from the outside. In addition it gets destroyed when the scope it belongs in stops being relevant - usually when a function call ends.
Loop is a control structure that repeats the instructions contained within it either a certain number of times or until some condition is no longer met. Loops can be used to return program execution to a previous point, and they can also be used for processing large number of values. Python has two kinds of loops: for and while.
Loop Variable is a variable that's introduced in for loop declaration. This variable will receive each value in the sequence (e.g. list) that is being iterated over in the loop. Its value changes on each iteration. A simple example from the material: for animal in animals: where animal is the loop variable. If the sequence contains tuples (or lists), a for loop can also have multiple loop variables: for student, grade in grading:. Loop variables are not inside their own scope and must therefore be distinct from other names inside the same function's scope.
Main program is the part of the code where the real execution of the program starts. As a rule of thumb any statements and control structures that are attached to the left boundary are part of the main program. Main program is usually at the very end of a code file and usually inside if __name__ == "__main__": statement. However do not use this statement in the earlier exercises because then the checker cannot execute your program's main program.
Merkillä (engl. character) tarkoitetaan ohjelmoinnissa yksittäistä datana esiintyvää kirjainta, numeroa, välimerkkiä tai muuta vastaavaa symbolia. Pythonissa merkki edustaa pienintä merkkijonon yksittäistä palasta.
  1. Description
  2. Esimerkit
Merkkijono (engl. string) on tietotyyppi, joka sisältää tekstiä. Sitä käytetään erityisesti käyttäjän kanssa viestimiseen. Merkkijonojen sisältöä voidaan myös tallentaa tiedostoihin. Pythonissa merkkijono merkitään lainaus- tai heittomerkillä (esimerkiksi "aasi" tai 'aasi'). Suosimme ensimmäistä. Merkkijono voidaan merkitä myös kolmella merkillä jolloin se voi olla monirivinen – tätä käytetään erityisesti dokumenttimerkkijonojen (docstring) kanssa. Merkkijono on muuntumaton tietotyyppi – kaikki, mikä näennäisesti muokkaa merkkijonoa, tosiasiassa luo (ja palauttaa) siitä muutetun kopion.
  1. Description
  2. Examples
Method is a function that belongs to an object, i.e. it's one of the object's attributes. Methods are often used by objects to change their own state somehow, or derive another value from themselves. When a method is called it is prefixed with the object that ownds it: choice.lower(). Methods are occasionally called "member functions" as well.
Method Call is a similar process to function calls. As a significant different the target object is defined by prefixing method name with it whereas it would be given as an argument in a function call. In a typical method call an object operates on itself. For instance word.upper() is a method call that operates on the object referred to by the word variable.
Module is basically any Python code file. Although more commonly module is used as a synonym for library. Typically a module contains functions and potentially other (like constants and classes) things that are connected to a certain domain or use case. Large programs are also often split into modules so that each module focuses on one aspect of the program.
  1. Description
  2. Examples
Python objects can be divided into two types: mutable and immutable. Mutable objects can have their values changed during program execution e.g. as the result as a method call. The most common example of a mutable object is a list: hogwarts.append("Hufflepuff") changes a list named hogwarts by adding a new value to it. Any references to this list later in the program will access the contents that now include "Hufflepuff".
  1. Description
  2. Esimerkit
Pythonissa objektit erotellaan muuntuviin ja muuntumattomiin. Muuntumaton (engl. immutable) arvo on sellainen, jonka sisältö ei voi muuttua - kaikki operaatiot jotka näennäisesti muuttavat arvoa tosiasiassa luovat siitä uuden kopion, joka yleensä sijaitsee uudessa muistipaikassa. Esimerkiksi merkkijonot ovat tyypillinen muuntumaton tyyppi Pythonissa. Siksi merkkijonojen kanssa näkee yleensä jotain tällaista: valinta = valinta.lower()
Ohjelmointikielissä on oleellista ymmärtää määrittelyn (engl. definition) ero suorittamiseen. Määrittelemällä luodaan kuvauksia funktioista, muuttujista ja erilaisista tietorakenteista – tavallaan siis kerrotaan ohjelmointikieltä käyttäen, minkälainen jokin edellä mainituista asioista on, tai mitä sen kuuluisi tehdä. Pythonissa määrittelyn ja suorittamisen ero on helpoin ymmärtää funktioiden avulla. Funktiomäärittelyssä funktio vasta luodaan – ikään kuin tehtaalla koottu laite. Funktiota varsinaisesti käytetään – eli sen toiminnallisuus hyödynnetään funktiota varten määriteltyä koodia ajamalla – vasta funktiokutsun yhteydessä. Samaa vertausta käyttäen funktiokutsu vastaa siis sitä hetkeä, kun tehtaalta saapunut laite käynnistetään.
Nimikonflikti syntyy, jos useammalle kuin yhdelle arvolle koitetaan antaa sama nimi. Tällöin tapahtuu niin, että tuoreempi sijoitus jåä voimaan. Tästä seuraa yleensä ohjelman kaatavia virheitä, koska usein arvot ovat eri tyyppiä. Voi jopa käydä niin, että epämääräisesti nimetyn funktion päälle tallennetaan vahingossa saman niminen muuttuja.
Namespace is a group of names (variables, functions, constants etc.) that belong to the same context. For example the names inside a function (inside the function definition code block) form their own namespace: names inside the function are only accessible from within. There's also a global namespace which is the main program's namespace. Using normal import in a program creates a new namespace within that program that is accessible through the module's imported name - the names inside the module form their own namespace. See also: Scope.
Newline (line break, end of line, EOL), the "\n" character is a character that, when printed or written to a file produced a line break. If a string is inspected without printing it e.g. in the console, all line breaks are shown as "\n" characters.
  1. Description
  2. Esimerkit
Nimeämätön vakio tai taikaluku (engl. magic number) on koodissa esiintyvä literaaliarvo, jota ei selitetä millään tavalla. Hyvään ohjelmointityyliin kuuluu taikalukujen välttäminen. Oikea – itsedokumentoiva – tapa on nimetä koodissa esiintyvät vakiot muuttujiin, jolloin niiden muuttaminen onnistuu tarpeen tullen yhdestä paikasta yhdellä muutoksella, ja koodin lukijan on helpompi ymmärtää koodia.
  1. Description
  2. Syventävää nippelitietoa
Näppäimistökeskeytyksellä (engl. keyboard interruption) voi pakottaa jumiin jääneen ohjelman sammumaan. Sen saa aikaan painamalla Ctrl+C sen terminaalin ollessa auki, jossa ohjelma pyörii. Pythonissa näppäimistökeskeytyksen saa käsiteltyä kaappaamalla KeyboardInterrupt-poikkeuksen try-except-rakenteella.
Objekti (engl. object), joskus myös olio, on Pythonissa yleistä terminologiaa. Kutsumme objekteja pääasiassa arvoiksi alkeiskurssilla, mutta Pythonissa kaikkea voi käsitellä objekteina. Tämä tarkoittaa, että mihin tahansa voidaan viitata muuttujilla (esimerkiksi funktion voi sijoittaa muuttujaan). Tämän kurssin puitteissa objekti-termiä käytetään sellaisista arvoista joilla on metodeja.
Objektit nousevat merkittävämpään rooliin alkeista eteenpäin, erityisesti koodissa jossa käytetään luokkia.
Ohjelmointityyli (engl. programming style) on joukko ohjeita tai tapoja, joita ohjelmoija noudattaa koodia kirjoittaessaan. Näihin tapoihin lasketaan muun muassa sisennyksen syvyys, muuttujien ja funktioiden nimeämiskäytännöt, välilyöntien käyttö lauseissa sekä monet muut tyyliseikat. Ohjelmointityylejä on useita erilaisia, ja tällä kurssilla opetetaan noudattamaan tiettyjä tyyliin liittyviä sääntöjä.
Ominaisuus (attribute) liittyy objekteihin siten, että objekteilla voidaan sanoa olevan ominaisuuksia. Tällä kurssilla useimmat näistä ominaisuuksista ovat metodeja, mutta ne voivat olla myös arvoja. Objektin ominaisuutta käsitellään notaatiolla, jossa objektin nimen ja ominaisuuden nimen väliin tulee piste, esim: valinta.lower()-metodikutsussa valinta on objekti ja lower on ominaisuus.
  1. Description
  2. Examples
Opening mode is used for telling Python (and the operating system) how to open a file. A file can be opened for reading or writing. By default, if opening mode is not given, a file will be opened in reading mode "r". There are two writing modes:
  • "w", write, which overwrites anything that may have been in the file previously with the new content.
  • "a", append, which writes the contents to the end of an existing file instead
Both writing modes create the file if it did not exist previously.
Operand is the fancy name used in mathematics and programming for values that are used in an operation. E.g. 5 + 8 is an addition operation and its operands are 5 and 8. Operands can be thought of as the subjects of operations.
  1. Description
  2. Examples
Operation is a term used for anything carried out by an operator in the code. Mathematical operations are typical examples. An operation consists of an operator and one or two operands. For instance 5 + 5 is an operation.
Operator is a name for symbols that define an operation in mathematics and programming. Operators always appear with at least one operand, but often two. An example of an operator would be + symbol which denotes an addition operation.
An argument in a function call is an optional argument if its corresponding parameter has been given a default value. This means that it's possible to call the function without giving that argument. If there are multiple optional arguments for a function, they are often given using keyword arguments.
Parameter is a variable defined along with a function. They are variables that are assigned values from arguments when the function is called. In other words when values are transferred in a function call, they are called parameters from the function's point of view. E.g. in def prompt_input(question, error_msg): question and error_msg would be parameters. Parameters can also have a default value that will be used as its value if the matching argument is not given in a function call - this makes the argument optional.
Parametrization means expanding the use cases of a process by turning some of its values into variables. This way the same process can be repeated for multiple sets of values with different results. Mathematical functions are one kind of parametrization: all points represented by the function are produced by changing the value of a variable (e.g. x). In programming parametrization is quite concrete because usually a procedure is turned into a function. The function's parameters then define which values are not fixed and the function will behave differently with different parameters.
  1. Description
  2. Examples
Path is the location of a file or folder on the hard drive. A path can be absolute or relative. Absolute path includes every folder from the target all the to the root (e.g. in Windows the root is the drive letter, like C:) whereas relative only includes folders up to the active folder (i.e. the folder where the program was started in). Path is usually presented in programming languages as a string, and path parts are separated with slashes /. When forming path inside code, it's best to use the join function from the os.path module.
  1. Description
  2. Additional formatting
Placeholder is by general definition a way to mark a spot that will be replaced by something else later. In this course they are primarily used with string formatting. A placeholder within an formatting string is marked with curly braces (f"Hi {name}"). Placeholders in strings can also contain additional formatting specifiers like setting the number of decimals to show (f"Donkeys have {average:.2f} legs on average"). When a placeholder is resolved, it is replaced by the value of the variable or statement inside the curly braces.
  1. Description
  2. try-except-else-finally
Poikkeusten käsittely (engl. exception handling) on ohjelmointikieleen sisäänrakennettu keino ohjelmoijalle reagoida poikkeuksiin. Pythonissa poikkeusten käsittely onnistuu try-except-rakenteella, jossa sekä try: että except: aloittavat omat lohkonsa; try-lohkon alle kirjoitetaan se koodi, joka mahdollisesti aiheuttaa jonkun tietyn poikkeuksen ja except-lohkon alle taas se koodi, joka suoritetaan siinä tapauksessa, että kyseinen poikkeus tapahtuu. Joissain muissa ohjelmointikielissä except-avainsanan sijaan käytetään avainsanaa catch, minkä takia yleisesti puhutaan poikkeusten kiinni ottamisesta.
Precedence, of math fame, defines in which order various operations in a statement are resolved.
result = 10 + 2 * (2 + 3)
The result of this statement is 20 because the sum of 2 and 3 is resolved first, followed by multiplying the result by 2, and finally adding the multiplication result to 10. In this example the highest precedence is held by the operation in braces, followed by multiplication, and then finally addition.
Precedence defines the execution order of instructions or operations on a line of code. Operations of different type have different precedence in execution order. These can be found from the link below. Operations with same precedence are executed from left to right. Like in mathematics, the order can be changed by using parentheses.
  1. Description
  2. Examples
Printing is somewhat different in programming context - although not really that far removed - from combining paper and ink to pages. In context of computer programs it usually means producing text on the screen, especially to a terminal. Python has a function for this purpose: print(...) that prints its argument(s) to the terminal.
Programming problem is the goal of a programming task. It is therefore some sort of a need that has been recognized and a program is coded to fulfill that need. The need can be e.g. automatization of a task, creating a web site or just making a fun game.
  1. Description
  2. Examples
Interactive Python interpreter or Python console as we like to call it is a program that executes Python code lines as they are written into it. It shows the return value of the line if any exists (e.g. the result of a mathematical operation). On this course we use IPython instead of the vanilla Python console. After installation you can start IPython by typing ipython to the terminal.
Python interpretetr is a program that transforms Python code into instructions to the computer's processor. It's responsible for executing both code files and individual lines in the Python console. The word can also be used to mean Python console though, so be careful.
  1. Description
  2. Examples
Recursion is a common programming term that refers to a function calling itself. Recursion is a function-based way to create repetition in the code where the function gives itself new arguments and handles its own return values. Recursion is handy e.g. when navigating tree-like structures - one "branch" is handled at a time, and then recursion is used to handle branches branching out from that branch, and so on. Recursion is not very widely used in Python. One reason is the recursion depth limit which restricts how many times a function can call itself.
Referring is the method in which a variable is connected to its value. The target of the reference is the computer's memory and the variable itself - under the hood - contains an address where from memory the value can be found.
Relative path is an operating system concept that indicates the path to a file or folder from the current folder. Relative paths do not care what kind of a garden maze of folders exists between the disk drive root and the current path. For this reason relative paths are usually used to refer to a program's own sub folders. This allows the program to be moved to another location without updating any paths in the code.
  1. Description
  2. Examples
Return is a process that happens when a function's execution ends. Typically the value(s) returned by the function are defined inside the function with a return statement. In the code that calls the function, the return value will replace the function call and can therefore be assigned to a variable or passed on to another function.
Return value is the value (or values) that a function returns when its execution ends - the function's result. Functions in Python can have multiple return values. When reading code you can regard return value as something that will replace the function call when the function execution has ended. A return value is defined inside a function with the return statement. E.g. in return True there is one return value: the literal boolean value True.
Sapluuna (engl. template) on muotti esimerkiksi tekstille, joka käyttäjälle halutaan näyttää, mutta joka ei semmoisenaan ole vielä valmis. Sapluunasta siis puuttuu tietoa, joka on tarkoitus saada sapluunan paikanpitimien tilalle.
Kurssilla yleisin sapluuna on merkkijono, jossa on paikanpitimiä format-metodia varten.
  1. Description
  2. Examples
Scope is a concept related to the visibility of names (variable, function etc.) in certain parts of the program. For instance within a function block any names defined inside the function can be used because they belong to the same scope. Other functions cannot access these names because they belong to a different scope. Names in the global (main program) scope can be accessed from anywhere in the code.
  1. Description
  2. Examples
Separator is a term related to strings and text files. It means a specific character that is meant for indicating a split inside a string when it is read into the program. For instance, if a string contains values that will be parsed into a list, the separator is the character than indicates where one part ends and the next one begins. The split method is often used in these situations - the method can use a specific separator to split a string into a list.
A sequence is any value in Python that is a series of things - for instance, string, list and tuple are all sequences.
  1. Description
  2. Examples
Slicing is the act of taking a new sub-sequence out from an existing sequence (usually list, but sometimes also string). The result of slicing is a value with the same type that's a copy of the selected part in the original sequence. The selection is done by choosing start and end indices. Both are optional. A slice is written as follows: page = collection[5:10] - this would make a slice including indices 5...9. The number on the right side of the colon in a slice is the first index that is not included in the result!
Slicing never causes an IndexError.
Solution model is an abstract construct developed by a programmer regarding how the solution to a programming problem works. It's not code yet, but it should be explicit and dividable into distinctive steps so that it can be turned into a program. Solution models can be sketched inside one's mind, by using paper and by trying this out in the Python console.
Source code or code means text that has been written with a programming language.
State, as the name suggets, referes to the program's current state. In practice state covers everything belonging to the program's state space like variable values, data in files, and where the code execution is currently at. A guaranteed way to make spaghetti code that's beyond repair is to use the global state - a crime that's perpetrated by functions that use global variables.
Later, on courses that go more formally into programming concepts, you'll learn of things like state machines, as well as stateless and stateful programs.
  1. Description
  2. Examples
Stub function is a function that's been defined properly with all the parameters etc. but has no content in it. They are typically put into the program code when planning its overall structure. Doing so allows the functions to be called elsewhere in the code while the function isn't fully implemented yet. The contents of a stub function usually come down to just pass, an informative print, or returning some placeholder default value. In larger projects stub functions sometimes are set to raise a NotImplementedError exception which makes it easy to locate the function that's not ready yet.
Syntax is the grammar of code. It defines what kind of text counts as valid Python. If code doesn't conform to the correct syntax, it cannot be executed. Syntax also informs a programmer about the correct formatting for each stement in the programming language.
Syntax error is an exception that happens when the Python interpreter inspects a code file before executing it and notices something broken in there, i.e. code that is written incorrectly. A code with syntax errors is not run at all.
One common syntax error is unbalanced parentheses. This results in a strange error message in the sense that Python reports the next line as the cause of the error. Remember to check previous lines as well when you receive strange syntax errors!
Takaisinkutsu (engl. callback) on yleinen ohjelmoinnissa käytetty menetelmä, jossa funktio ottaa parametrin kautta vastaan funktion kutsuttavakseen heti (synkroniset takaisinkutsut) tai joskus tulevaisuudessa (asynkroniset takaisinkutsut). Nimensä menetelmä on saanut soittopyynnöstä: kutsuttavaa funktiota, jolle jokin funktio välitetään argumenttina, ”pyydetään” kutsumaan tätä annettua funktiota. Pythonissa listojen sort()-metodin key-parametri on esimerkki callback-funktioiden käytöstä. Usein käyttöliittymiä toteutettaessa käyttöliittymäelementteihin kytketään callback-funktioita.
Terminal, command line, command prompt and shell' are different names to the text based interace of an operating system. It is used for text-based operating system commands and for running terminal programs. On this course we mostly move around with cd (change directory) and use ipython command to run code files and start the Python console.
  • In Windows you can open the terminal by typing cmd to the start menu search
  • In Mac OS X you can start the terminal by typing terminal to Finder
  • In Linux you can open the terminal from the desktop by pressing Ctrl + Alt + T or by typing terminal to the search
Testaamalla eli kokeilemalla (engl. test) selvitetään, toimivatko hartaasti näppäillyt koodirivit halutulla tavalla. Testejä suorittamalla siis etsitään koodista mahdollisia ohjelmointivirheitä. Ohjelmien testaaminen on jopa niin olennaista, että joidenkin alan työntekijöiden tehtävänä on ainoastaan automatisoitujen testien ohjelmointi. Lovelace-järjestelmän tarkistimet testaavat järjestelmään lähetetyt koodit.
Generally text file is any file that can be read with a text editor. In this course's context we use text file to refer to files that are handled as text inside Python. We do this to separate them from code files that are run with Python. Text files are used in this course to store data between runs of the program.
Tosi (engl. true) on toinen kahdesta mahdollisesta totuusarvosta ja toisen, eli epätoden, vastakohta. Sitä voidaan pitää lopputuloksena loogisissa ja vertailuoperaatorioissa, jotka pitävät paikkansa. Esimerkiksi vertailuoperaatio 5 > 4 pitää paikkansa, joten kyseinen operaatio evaluoituu todeksi. Pythonissa totta merkitään avainsanalla True.
  1. Description
  2. Esimerkit
Traceback is the process of tracing an error back to its source. When an exception occurs the Python interpreter prints an error message that includes a traceback. It's presented as a stack of function calls where the last one is the funtion where the exception occurred. They are also called stacktrace for this reason. For example if the main program calls the funcion f which in turn calls function g where the exception occurs, the stack would be
main programfg.
  1. Description
  2. Examples
Tuple is a co-called frozen list. It's an ordered collection of values like a list but it's an immutable object. A tuple can't be changed. They can only be created, and read. Usually a tuple is delimited with normal braces: "#!python3 (1, 2, 3) but actually this is a tuple even without them: 1, 2, 3.
Unlike lists, tuples can be used as dictionary keys.
  1. Description
  2. Examples
Type conversion (also type casting and type coercion) means changing the type of a variable or literal value to another one. In Python this is commonly done when a number is requested from the user and it is returned as a string. In practice this can be done with e.g. int("123") or float("3.14"). In some cases Python performs type conversion automatically, usually when mathing with floats and integers.
Tyylisäännöt ovat kokoelma suosituksia, joiden mukaan koodia tulisi kirjoittaa. Kullakin kielellä on yleensä omansa. Tyylisääntöjen rikkominen ei varsinaisesti riko ohjelmaa, mutta tyylisääntöjen mukainen koodi on miellyttävämpää lukea ja usein tästä johtuen myös helpompi korjata. Tällä kurssilla seurataan Pythonin virallista tyylistandardia erityisesti tekstikenttätehtävissä. Myös tiedostotehtävissä on koodin laadun tarkistus, jossa käytetään PyLint-ohjelmaa.
  1. Description
  2. Esimerkit
Tyyppi (engl. type) on arvon ominaisuus – jokainen arvo edustaa aina jotain tiettyä tyyppiä. Tyypin tarkoitus on siis kertoa, minkälaisesta arvosta on kyse. Käytännössä tästä seuraa myös se, mitä operaatioita arvoilla voi tehdä, ja mitä metodeja niiltä löytyy. Funktiot on myös miltei aina toteutettu siten, että niille syötettävien argumenttien täytyy olla tietyntyyppisiä, jotta funktio voisi toimia. Tyypit ovat yksi ohjelmoinnin keskeisimmistä käsitteistä.
Pythonissa arvojen sopiminen koodista löytyviin operaatioihin tarkistetaan tilannekohtaisesti näiden arvon ominaisuuksien perusteella – ei siis suoraan itse tyyppiä tarkastamalla. Esimerkiksi useimmissa tapauksissa kokonaisluku ja liukuluku kelpaavat molemmat, mutta on myös tapauksia, joissa näin ei ole (esimerkiksi merkkijonoa ei voi kertoa liukuluvulla).
Tällä kurssilla tyypillisiä tyyppejä ovat kokonaisluku (int), liukuluku (float), merkkijono (str), lista (list), totuusarvo (bool) ja monikko (tuple). Myös funktioilla on oma tyyppinsä!
User Interface (UI) is the interface between a program and its user (typically human). In a simple text based UI input function calls are used to prompt things from the user and print calls can be used to display instructions and results.
Many programs intended for end users (consumers) typically offer a graphical user interface (GUI). These typically involve icons, popup menus and other elements that can be poked with by mouse or touch screen. On this course we will take a very shallow stab at graphical user interfaces in the final project.
A simplified way to describe variable is to think of it as an information storage - it contains something. This expression is often used in speech even though it's not entirely accurate. The more accurate description is that a Python variable is a reference to a value. It's a connection between the variable's human-readable name and a value that's stored in the computer's memory. So the variable in fact doesn't contain the value, it just contains information about where it is.
  1. Description
  2. Examples
The break keyword is a special instruction that is used in loops. It interrupts the loop's execution immediately, and code execution continues from the first line after the loop. If the loop had an else branch, it is not entered.
  1. Description
  2. Examples
continue is the other keyword related to loops (the first one being break). Unlike break which interrupts the entire loop, continue only interrupts the current iteration - execution continues from the next iteration. Note that this keyword is only needed in situations where part of the iteration is to be skipped. There's no need to put continue to the end of the loop iteration.
  1. Description
  2. Examples
enumerate is builtin function that produces a generator-like object in Python. Its primary use is in for loops when the code needs to access the items' indices in addition to the items themselves. The enumerate object produces tuples where the first item is the original item's index and the second item is the original item itself. Use example: for i, character in enumerate(moomin_valley):.
f(ormat) string is a special string that is used for inserting values from variables or simple clauses inside a piece of text. This is also called string interpolation in programming terminology. This kind of a string is marked by prefixing it with a lowercase f. You can include placeholders inside the string by using curly braces, and writing variable names or clauses inside them.
Example: f"Interval between donkey's ears is {measurement:.2f} inches" (assuming that a variable named measurement has been definied previously)
  1. Description
  2. Examples
In Python for is one of the two loop types. It's designated for iterating through data structures. It is used especially with lists. In general, for loops are used when it's possible to determine in advance how many iterations the loop must do. In addition to iterating through structures, for loop is therefore used for doing a certain number of iterations (e.g. 10 iterations). For loop declarion looks like for item in collection: where item would be the name of the loop variable, and collection would be the data structure that is being iterated over.
  1. Description
  2. Examples
In Python modules are "activated" by import statements. In normal use (e.g. import math) the statement makes a new namespace accessible through the module name. Functions from the imported module can be accessed through its name. It's also possible to directly import some specific names from a module with a from-import statement: from math import ceil. Modules can also be renamed on import: import math as m.
  1. Description
  2. Esimerkit
Silmukoista while pohjautuu toistoon ehdon tarkastelun kautta - silmukan sisällä olevaa koodilohkoa suoritetaan niin kauan kuin silmukalle annettu ehto on tosi. Ehto määritetään samalla tavalla kuin ehtolauseissa, esim: while summa < 21. While-silmukat soveltuvat parhaiten sellaisiin tilanteisiin, joissa ei voida etukäteen selvittää montako toistoa tarvitaan - erityisesti syötteiden kysyminen käyttäjältä on tällainen tilanne.
  1. Description
  2. Examples
In Python with is a somewhat exception keyword in that it's not a control flow structure or definition of a new thing. On this course it's primarily used when opening files, e.g. with open("donkey.txt") as somefile:. All read or write operations on the file are carried out inside the with statement. When the with statement ends, Python automatically takes care of closing files opened in the with statement.