Introduction

In this tutorial, the topics variables, values, operators, functions and encryption and decryption will be treated. Mainly, the basics of each topic will be introduced eventhough there would be a lot more to learn in each topic. However, if you are new to coding in Python, this tutorial is suited for you as it should help you understand the basics, which is key, before going into more advanced coding. Bear in mind that one could go into more detail for these concepts: If you are interested in learning more to a topic either refer to our links which lead you to external, more in-depth sources or use Google as you can find mostly anything related to Python online. However, before you do this: Make sure you understand the basics presented in this tutorial and that you can apply them.

To the content of this tutorial: First, variables are looked at. Variables are key in any programming language and often serve as placeholders so that algorithms or functions can be coded and later on used for different values. An algorithm is a step-by-step approach on how to solve a problem. A function relates input to output. Without variables, the code would need to be rewritten for any new value which is rather cumbersome. You can assign different values to a variable as for example a number or a string which is a list of numbers and characters.

Second, values are introduced. Values are whatever is assigned to a variable. There are several types of variables, such as: strings, numbers or booleans. A boolean is the result of a logical statement, hence a boolean either takes the value true or false.

Third, operators are treated. Operators are used to perform mathematical operations on one or more variables or values. They are nothing else than functions which are already built in in Python. Like values, operators are classified into different types: For example, arithmetic operators such as + and -.

Fourth, functions are introduced. Functions generally make coding more efficient as they can be used for solving similar problems for different inputs. There are different kinds of functions which can be used in Python: Either those which you code and later on call (=use) yourself or the ones that are already built-in in Python: as for example the function print(), which returns whatever is written in parantheses. Additionally, there also exist functions within so-called libraries or packages which first need to be imported into Python.

Fifth, encryption and decryption are treated. Encryption and decryption are cryptographic algorithms which can be used for sending secret messages that can only be read by the recipient provided he or she is knowledgeable about the applied algorithm. Encryption is the algorithm which transforms a plain, legible text into an encrypted, unintelligible text. The algorithm which makes encrypted text again intelligible is referred to as decryption.

In the end, a conclusion is provided which sums up the key takeaways of this tutorial such that you can check whether you understood the tutorial's content or whether you have to go over certain parts again.

Variables

A variable can be thought of as reserved memory space in the kernel which stores a value. Remember from the previous tutorial; the kernel is where the code gets executed and where variables are stored. In other words, when a variable is defined, some space in the memory of the kernel is reserved for that particular variable. When this variable is called, whatever is saved within the related memory space is returned. For a start, how to define a variable and then how to call/use a variable is explained.

(Note: This chapter contains verbatim quotes from: https://www.programiz.com/python-programming/variables-constants-literals)

Define a variable

Use the equality sign = to define variables: The value to the left of the equality sign is used as the name of the variable and the value on the right of the operator is used as the value stored in the variable (or more exact in the memory space which is referred to as the variable). Example:

a = 1

The variable would be named a and the value assigned to it would be 1.

In [1]:
# You can run the code in this cell as an example.
# Change the values for the variables a, b and c and check whether the output of the code changes

a = 1
b = 2
c = -3

print(a) # As you can see: print() simply returns whatever is given within the parentheses

print(b)

print(a, c)
1
2
1 -3

Name a variable

When naming a variable or in other words, when chosing whatever is written on the left-hand side of the equation, you are relatively free. However, the following rules should be adhered to:

  • Use lowercase characters,
  • avoid non-letter characters (like !,&, %,,...),
  • underscore and numbers can be used, but not at the beginning of the name,
  • keywords (e.g. if, while, return,...) cannot be used as a name,
  • be as explicit as possible.

Multiple assignment

It is possible to assign a single value to several variables simultaneously. Example:

x = y = z = 5

This assigns the value 5 to the variables x, y, and z.

In [2]:
x = y = z = 5

print(x)

print(y)

print(z)

print(x+y+z)
5
5
5
15

Pay attention: If, for example, the value 5 gets assigned to x, and x gets assigned to f. Then if a different value gets assigned to x, f still refers to the memory space that x previously referred to and not to the new memory space. This is because Python runs code line by line.

In [3]:
x = 5 # 5 is assigned to the variable x
f = x # x is assigned to the variable f

print(x, f) # both variables refer to the same value (5), as f refers to the memory space of x

x = 10 # 10 is newly assigned to x

print(x, f) # x equals newly 10, however, f still refers to the old memory space of x, hence to 5

# This can be avoided by rewriting f = x after newly defining x:

X = 10
f = x

print(x, f)
5 5
10 5
10 10

It is also possible to define several variables at once, in one line of code. To do so, separate the individual variables and the values assigned to them by commas.

In [4]:
x, y, z = 5, 6, 7

print(x)

print(y)

print(z)

print(x + y + z)
5
6
7
18

Call a variable

The value that is assigned to a variable can be called by using print() and in parantheses the name of the variable. The advantages of using variables instead values are the following:

  • Makes code more readable,
  • Avoids repetition of values,
  • Functions can be re-used for different values,
  • Complex formula can be read easier.

Example: capital = 10 000, interest = 0.05, periods = 12

$future value = capital \cdot (1 + interest)^{periods}$

In this example, the variables are chosen in a way that they help to understand a function or formula better. The values assigned to the variables can be changed quickly such that the formula can be re-used.

Here an example on how you can use print() to call your variable:

In [5]:
a = 2

print(a + a ** a + (a / a))
7.0

Values

Every program written in Python (or in any programming language) operates on data. A single piece of information or data can be referred to as a value. In Python, values are grouped into different data types or so-called classes. The function type() returns you the class a value belongs to. Not all possible types of values will be discussed here, however, the most important ones are looked at:

  • Strings
  • Numbers
  • Boolean
  • Lists
  • Tuples
  • Dictionaries

(Note: This chapter contains verbatim quotes from: https://realpython.com/python-data-types/ and https://developer.rhino3d.com/guides/rhinopython/python-datatypes/ and http://dataanalyticsedge.com/2018/05/08/basics-of-python/)

Types of values

Strings

The value type string refers to lists of characters, spaces and numbers that can form words and sentences. However, they do not need to make linguistic sense to be strings. They are written within quotation marks: Pairs of single or double quotes are usually used. Examples of strings are: "Hello World!", "I am 20 years old." and "alskdfj2983".

Here are a few basic operations for strings (in the code below, it can be seen how they are applied):

The plus sign + is used to add up different elements of the string and the asterisk * is the repetition operator: To indicate how often a string should be repeated. Multiple strings can either be combined with the + sign, commas or with the function .format().

To break up a string over more than one line, include a backslash \ before each new line. Inversely, to receive a string that goes over multiple lines, one can make a line break in Python by adding a backslash with a small n \n at the respective point.

A convenient way to create a string with both single and double quotes in it, is to create a triple-quoted string: In this way, new lines can be created.

In [6]:
# We use the print() function to tell Python to output strings 
print("Hello World")
print("Numbers such as 1234 can also be printed as part of a string.")
print("We can also separate text by using commas", " as shown in this line of text.")
print("We can also use plus signs" + " to add text fragments to each other.")
print("Pay attention to ", " spaces" + "when adding text", "so your out " + " put does not contain any", "typos.")

# Format function
a = 5
b = 4
c = 3
print("Number a is {}. Number b is {}. Number c is {}.".format(a,b,c))

# Splitting up a string over multiple lines
print("a\
b\
c")

# Output multiple lines with a one-line string
print("a\nb\nc")

# Triple Quoted String
print("""This
is a "really"
convenient 'way' of
adding multiple lines.""")

# Addition and multiplication of strings
text = "Hello"
print(text + text) # This will output the sentence twice
print(text * 3) # This will output the sentence three times

# How to subset a string
text = "Switzerland is so small!"
print(text[0]) # creates the subset S which is the character position 0
print(text[0:11]) # shows the subset Switzerland, the character position 0 to 10
Hello World
Numbers such as 1234 can also be printed as part of a string.
We can also separate text by using commas  as shown in this line of text.
We can also use plus signs to add text fragments to each other.
Pay attention to   spaceswhen adding text so your out  put does not contain any typos.
Number a is 5. Number b is 4. Number c is 3.
abc
a
b
c
This
is a "really"
convenient 'way' of
adding multiple lines.
HelloHello
HelloHelloHello
S
Switzerland

Functions for string operations

In Python there are several built-in functions (what a built-in functions is, will be treated in a upcoming section called functions) which are useful for operations with strings. However, as these so-called methods are type-specific, these functions can only be used for strings.

The most important methods are depicted in the following list:

Function Description
strip() removes any whitespace from the beginning or end
len()  returns the length of a string
lower() returns string in lower case
upper()  returns string in upper case
replace()  replaces string with another string
split() splits tring into substring if it finds instrances of the seperator

Here are examples showing how to apply these functions:

In [7]:
a = "  Hello, World!"
print(a.strip( )) # takes away / "strips away" any superfluous spaces

b = "Hello, World!"
print(len(b)) # counts elements within string (elements = characters, spaces, signs, numbers)
print(b.lower())
print(b.upper())
print(b.replace("W","Z"))
print(b.split(","))
Hello, World!
13
hello, world!
HELLO, WORLD!
Hello, Zorld!
['Hello', ' World!']

Numbers

Another value type or class of Python are numbers. Python 3 supports three different numerical types:

  • int (integers)
  • float (floating point real values)
  • complex (complex numbers)

Normally, Python will convert a number automatically from one type to another if needed and this is fine most of the time. But under certain circumstances if a specific numeric type is needed, the format can be forced by using additional syntax from the table below:

Type Format Descrption
int() a = 10 Integer
float() a = 45.67 (.) Floating point real values
complex() a = 4-3j (j) Complex (imaginary) number

Integers

Integers are whole numbers, positive or negative, without decimals, of unlimited length such as: 2, 6, 2368, -78, -9746286.

Floats

Floats, or "floating point number" are numbers, positive or negative, containing one or more decimals such as: 1.1, 0.00025, 134.56, -78.64, -12000.7, 5.0

Floats can also be scientific numbers with an "e" to indicate the power of 10.

Complex Numbers

A complex number consists of an ordered pair of real floating-point numbers denoted by x + yj, where x and y are the real numbers and j is the imaginary unit. Examples: 2+45j, 9.322e-36j

Built-in mathematical functions and math package

Python supports many built-in funtions of which the most useful ones for this topic are presented in the following overview table:

Function Description
abs() Returns absolute value of the value; (positive) distance between the value and zero
divmod() Returns quotient and remainder of integer division
max() Returns the largest of the given arguments or items in an iterable
min() Returns the smallest of the given arguments or items in an iterable
pow() Raises a number to a power
round() Rounds a floating-point value

Other functions performing useful calculations in this context may also be appropriated by making use of the math library in Python. However, this must be imported into the code beforehand with import math. We will cover library in more detail in the part functions later on.

Consequently, an overview of important functions of the math-package is provided:

Function Description
math.ceil() Returns the ceiling of the value; smallest integer not less than the value
math.exp() Returns the exponential of the value; the euler number to the power of the value
math.floor() Returns the floor of the value; largest integer not greater than than the value
math.log() Returns the natural logarithm of the value for value > 0
math.log10() Returns the base-10 logarithm of value of value > 0
math.sqrt() Returns the square root of the value for value > 0
math.cos() Returns the cosine of the value radians
math.sin() Returns the sine of value radians
math.tan() Returns the tangent of value radians
In [8]:
# Integer numbers
print(10)
print(type(10))
print(0x50)
print(type(0x50))

# Float numbers
print(4.2)
print(type(4.2))
print(4.2e-4)
print(type(4.2e-4))

# Complex numbers
print(4+8j)
print(type(4+8j))

# Built-in Mathematical Functions of Python
print(abs(-5))
print(divmod(17,6))
print(max(4,3,7,4,9,2,3))
print(min(4,3,7,4,9,2,3))
print(pow(4,2))
print(round(14.7))

# Math package functions
import math
print(math.ceil(5.6))
print(math.exp(4))
print(math.floor(4.9))
print(math.log(150))
print(math.log10(125))
print(math.sqrt(2))
print(math.sin(30))
print(math.cos(85))
print(math.tan(22.5))
10
<class 'int'>
80
<class 'int'>
4.2
<class 'float'>
0.00042
<class 'float'>
(4+8j)
<class 'complex'>
5
(2, 5)
9
2
16
15
6
54.598150033144236
4
5.0106352940962555
2.0969100130080562
1.4142135623730951
-0.9880316240928618
-0.9843766433940419
0.5578517393521941

For further information on the value type numbers, click here or here.

Boolean

Boolean values are either True or False. They are usually the output of a function that includes a logical operator. Expressions in Python are often evaluated in a Boolean context, meaning, they are interpreted to represent truth or falsehood. We will explain later in the notebook what exactly a logical operator is, but simply put, it tests if a statement is true or not.

In [9]:
a = True
b = False
print(a)
print(type(b))
True
<class 'bool'>

Lists

Lists are the most versatile of Python's compound data types. A list contains items separated by commas and enclosed within square brackets []. In Python, any data type can be added to a list. Once a list is created using only integers as its elements, it is possible to add other value types, such as strings or booleans.

The values stored in a list can be accessed using the slice operator [] and [:] with indexes starting at 0 in the beginning of the list and working their way to end -1. The plus sign + is the list concatenation operator, and the asterisk * is the repetition operator.

To add elements to a list, we use the very useful method .append() that will attach a certain value to the end of the respective list.

Lists are not limited to a single dimension; a so-called list of lists is possible. Multiple dimensions can be declared by seperating them with commas. For instance, in a two-dimensional list, the first number is always the number of rows where the second number is the number of column.

For further information, click here.

In [10]:
# You can run the code in this cell to create lists, print them and to subset them.

number_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
string_list = ["Hello", ",", "how", "are", "you", "?"]
mixed_list = [1, "I", 5.6, "goodbye"]

print(number_list)
print(string_list)
print(mixed_list)
print(mixed_list[3])
print(number_list[5:])
print(string_list[:3])
print(mixed_list[0:2])

# Method .append()
mixed_list.append("XYZ")
mixed_list.append(4-5j)
print(mixed_list)

# Example of a two-dimensional list
my_list = [[5,3],[2,3]]
print(my_list)
print(my_list[0],my_list[1])
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
['Hello', ',', 'how', 'are', 'you', '?']
[1, 'I', 5.6, 'goodbye']
goodbye
[6, 7, 8, 9, 10]
['Hello', ',', 'how']
[1, 'I']
[1, 'I', 5.6, 'goodbye', 'XYZ', (4-5j)]
[[5, 3], [2, 3]]
[5, 3] [2, 3]

Tuples

A tuple is another sequence data type that is similar to the list. A tuple consists of a number of values separated by commas. Unlike lists, however, tuples are enclosed within parentheses.

The main differences between lists and tuples are: Lists are enclosed in square brackets [] and their elements and size can be changed, while tuples are enclosed in regular parentheses () and cannot be updated. Tuples can be thought of as read-only lists.

In [11]:
# You can run the code in this cell to create some tuples, print them and subset them
# In this example, the tuples behave exactly as lists would

number_tuple = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
string_tuple = ("Hello", ",", "how", "are", "you", "?")
mixed_tuple = (1, "I", 5.6, "goodbye")

print(number_tuple)
print(string_tuple)
print(mixed_tuple)
print(mixed_tuple[1])
print(number_tuple[5:])
print(string_tuple[0:5])
(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
('Hello', ',', 'how', 'are', 'you', '?')
(1, 'I', 5.6, 'goodbye')
I
(6, 7, 8, 9, 10)
('Hello', ',', 'how', 'are', 'you')
In [12]:
# The difference between lists and tuples becomes clearer, when we try to update the data contained therein

new_list = [1, 2, 2, 4, 5]

new_tuple = (1, 2, 2, 4, 5)

new_list[2] = 3
print(new_list)

new_tuple[2] = 3
print(new_tuple)

# It is possible to update the list, but not the tuple. Tuples are read-only.
# When running this cell, Python will display an error message, highlighting row 10
# Add a hashtag # symbol to row 10 and re-run the cell
[1, 2, 3, 4, 5]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-12-9156ad7a84a3> in <module>()
      8 print(new_list)
      9 
---> 10 new_tuple[2] = 3
     11 print(new_tuple)
     12 

TypeError: 'tuple' object does not support item assignment
In [1]:
# To update the tuple from the previous exercise, we need to recreate the whole tuple with the new values

new_tuple = (1, 2, 2, 4, 5)

new_tuple = (1, 2, 3, 4, 5)

print(new_tuple)
(1, 2, 3, 4, 5)

Dictionaries

Dictionaries are lists of Key:Value pairs. They are very helpful when related information is held that is associated through keys. The main operation here is to extract a value based on the key name.

Unlike lists, where index numbers are used, dictionaries allow for the use of a key to access its members.

A dictionary key can be almost any value type but is usually a number or string. Values, on the other hand, can be any arbitrary Python object. The Keys must, however, be unique in the respective dictionary.

Dictionaries are enclosed by curly brackets {} with different pairs being seperated by a comma , and associated with a colon :. The values can be assigned and accessed using square braces []. Inversely however, the keys cannot be accessed that when using the respective corresponding values.

Dictionaries have no concept of order among elements. It is incorrect to say that the elements are "out of order"; they are simply unordered.

Useful methods in the context of dictionaries are for example .keys() that prints only the keys of a certain dictionary or .values() that prints only the values of a certain dictionary.

In [2]:
# You can run the code in this cell to create a simple dictionary

d1 = {"Schweiz" : "Zürich", "UK" : "London", "Frankreich" : "Paris"}

print(d1)

print(d1["UK"])

print(d1.keys()) # Print only the keys of the dictionary

print(d1.values()) # Print only the values of the dictionary

# print(d1["Paris"])
{'Schweiz': 'Zürich', 'UK': 'London', 'Frankreich': 'Paris'}
London
dict_keys(['Schweiz', 'UK', 'Frankreich'])
dict_values(['Zürich', 'London', 'Paris'])
In [3]:
# Here is another example of a dictionary

GerEngDictionary = {"Hallo" : "Hello", "Auf Wiedersehen" : "Goodbye", "Gut" : "Good", "Schlecht" : "Bad"}

print(GerEngDictionary)
{'Hallo': 'Hello', 'Auf Wiedersehen': 'Goodbye', 'Gut': 'Good', 'Schlecht': 'Bad'}

Data Type Conversion / Variable Type Specification

Sometimes, conversions between the different data types or - more generally - value type specifications are necessary. To convert between types or specifcy variable types, you simply use the type name as a function.

There are several built-in functions to perform this task which will return a new object representing the final (converted) value.

Function Description
int() Converts to an integer
float() Converts to a floating-point number
complex() Converts to a complex number
str() Converts to a string representation
tuple(l) Converts l to a tuple
list (l) Converts l to a list
dict(t) Creates a dictionary, t must be a sequence of (key, value) tuples

Keep in mind, that not all conversions are possible, since they do not make sense. Converting a string into a float will not work through these in-built functions.

In [4]:
# Run the code in this cell to convert the data type of the variables below
# The function type() checks the data type of a variable. We use type() to show that the data type conversion worked

a = 4.0

print(type(a))
print(type(int(a)))

b = 5.0

print(type(b))
print(type(str(b)))
<class 'float'>
<class 'int'>
<class 'float'>
<class 'str'>
In [5]:
# Below is an example of a data type conversion that does not work
# The value assigned to the variable a is the string "four"
# Python does not understand the meaning behind the word four, so cannot complete the conversion

a = "four"

print(type(a))
print(type(int(a)))
<class 'str'>
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-5-0932c1c056c9> in <module>()
      6 
      7 print(type(a))
----> 8 print(type(int(a)))

ValueError: invalid literal for int() with base 10: 'four'

Operators

Operators are used when you want to perform mathematical operations on one or more variables or values. Operators are nothing else than functions which are already built-in in Python. Operators can be categorized into different types: Arithmetic, boolean, assignment, logical, membership and identity operators that are each discussed in more detail below. Another important aspect of operators, is how they are ranked, meaning if several operators are used in one line of code, which operators are executed first.

(Note: This chapter contains verbatim quotes from: https://www.tutorialspoint.com/python/python_basic_operators.htm)

Types of Operators

Arithmetic Operators

Arithmetic operators are basic mathematical functions. They work with number values, but some also work with strings and other values.

Symbol Name Description Example
+ Addition Adds values on either side of the operator 1 + 1 = 2
- Subtraction Subtracts values on right side of the operator from left side of operator 2 - 1 = 1
* Multiplication Multiplies the value on the right side of the operator with the value on the left side 2 * 3 = 6
/ Division Divides the value on the left side of the operator by the value on the right side 6 / 3 = 2
% Modulus Divides the value on the left side of the operator by the value on the right side and returns the remainder 7 % 3 = 1
** Exponent Performs exponential (power) operation on the value on the left of the operator 2 ** 3 = 8
// Floor Division The division of operands where the result is the quotient in which the digits after the decimal point are removed. But if one of the operands is negative, the result is floored, i.e., rounded away from zero (towards negative infinity) 9 // 2 = 4
In [6]:
# You can run the code in this cell to perform some basic math in Python

print(1 + 1)

print(2 - 1)

print(2 * 3)

print(6 / 3)

print(7 % 3)

print(2 ** 3)

print(9 // 2)
2
1
6
2.0
1
8
4
In [7]:
# It is also possible to combine these operators
# We will cover below the precedence the operators take. Keep in mind that expressions within parentheses are executed first.

print(2 + 3 * 2)

print((2 + 3) * 2)

print(5 ** 2 + 1)

print(5 ** (2 + 1))
8
10
26
125

Boolean Operators

Boolean operators compare the values on either sides and decide the relation among them. They are also called Comparison operators or Relational operators. The output of an operation with a Boolean operator will be a Boolean value True or False.

Symbol Description Example
== Checks if values on either side are equal 2 == 2 returns True
!= Checks if values on either side are not equal 2 != 3 returns True
> Value on the left greater than value on the right 5 > 2 returns True
< Value on the left smaller than value on the right 5 < 2 returns False
>= Value on the left greater or equal to value on the right 3 >= 2 returns True
<= Value on the left smaller or equal to value on the right 2 <= 2 returns True

Boolean operators cannot be used between all values. While it makes sense to compare an integer to a float, comparing a string to a float will lead to an error.

In [8]:
# You can run the code in this cell to use Boolean operators in practise

print(2 == 2)

print(2 != 3)

print(5 > 2)

print(5 < 2)

print(3 >= 2)

print(2 <= 2)
True
True
True
False
True
True
In [9]:
# In this code, Python can perform the comparison between a float and an integer
# However, the relation between a string and an integer will lead to an error

print(2.0 > 5)

print("three" > 2)
False
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-9-aa56a5689538> in <module>()
      4 print(2.0 > 5)
      5 
----> 6 print("three" > 2)

TypeError: '>' not supported between instances of 'str' and 'int'

Assignment Operators

Assignment operators are used to define variables or to update the value of variables. We have already used the most basic one, the equality sign =, to define functions.

Symbol Description Example
= Assigns value on the right side of the operator to the variable on the left side a = b assigns value of b to a
+= Adds value on right side of operator to value on the left and assigns the result to the value on the left a += b returns the same as a = a + b
-= Subtracts value on the right side of the operator from the value on the left and assigns the result to the value on the left a -= b returns the same result as a = a - b
*= Multiplies value on the right with the value on the left side of the operator and assigns the result to the value on the left a = b returns the same result as a = a b
/= Divides the value on the left side of the operator with the value on the right and assigns the result to the value on the left a /= b returns the same result as a = a / b
%= Divides the value on left side of the operator by the value on the right side and assigns the remainer to the value on the left side a %= b returns the same result as a = a % b
**= Performs exponential (power) operation on value on the left side and assigns the result to the value on the left side a **= 2 returns the same result as a = a ** 2
//= It performs floor division on operators and assigns value to the left operand c //= a returns the same result as c = c // a
In [10]:
# Run the code in this cell to use the Addition/Assignment operator

a = 1

b = 2

a += b

print(a)
3
In [11]:
# Run the code in this cell to use the Division/Assignment operator

a = 15

b = 5

a /= b

print(a)
3.0

Logical Operators

Logical Operators are used to reverse the logical state of its operand. They can also add conditions that need to be met for a statement to be true.

Symbol Description Example
and Adds a condition that needs to be met a < 4 and a > 2 only returns True if integer value of a is 3
or Adds alternative condition a < 4 or a < 2 will return True, if either condition is fulfilled
not Reverses logical state Not (a < 4 and a > 2) will return False if integer value of a is 3
In [12]:
# You can run the code in this cell to use the logical operators

a = 3

print(a < 4 and a > 2)

print(a < 4 or a < 2) # This statement returns True, since either condition can be fulfilled to return True
True
True

Membership Operators

Membership operators test if a certain value is part of a string, list or tuple.

Symbol Description Example
in Checks if a certain value is part of a certain sequence. Returns True if it is, otherwise it returns False a in b returns True if a is part of sequence b
not in Checks if a certain value is not part of a certain sequence. Returns True if it is not, otherwise (i.e. if the value is part of the sequence) it returns False a not in b returns False, if a is part of sequence b
In [13]:
# You can run the code in this cell to create a list and then check if certain values are part of the list

list = [1, 3, 5, 7, 9]

print(1 in list)

print(2 in list)

print(3 in list)

print(4 in list)

print(5 in list)

print(6 not in list)

print(7 not in list)

print(8 not in list)

print(9 not in list)
True
False
True
False
True
True
False
True
False

Identity Operators

Identity Operators compare the memory location of two objects.

Symbol Description Example
is Checks if the values on either side point to the same location in memory. If they do it returns True, otherwise it returns False a is b will return True if id(a) equals id(b)
is not Checks if the values on either side point to a different location in memory. If they do it returns True, otherwise (i.e. if they point to the same location in memory) it returns False a is not b will return True if id(a) does not equal id(b)
In [14]:
# You can run the code in this cell to create variables and check them against each other

a = 2

b = 3

c = 4

d = 2

e = 3

print(a is d)

print(a is b)

print(c is 2 * a)

print(b ** a is e ** d)
True
False
True
True

Ranking of Operators

Operators are executed in a certain order. Being aware of the priority that operators take when Python executes code is crucial. The table below shows which operations are executed first in descending order.

Precedence Operator Description
1 ** Exponentiation (Raise to the power)
2 * / % // Multiplication, Division, Modulo and Floor Division
3 + - Addition and Subtraction
4 > < >= <= Comparison operators
5 == != <> Equality operators
6 = += -= *= /= %= **= //= Assignment operators
7 'is' 'is not' Identity operators
8 'in' 'not in' Membership operators
9 'not' 'or' 'and' Logical operators

Functions

What are functions?

A function is a block of code which relates input to output and can be used for different inputs (variables, values).

One can either use self-created functions or already built-in functions in Python. Self-created functions refer to functions that are defined and coded by a person, while built-in functions are already pre-coded and can simply be applied. Some examples for built-in functions are:

  • print() - which returns whatever is written within the parantheses,
  • type() - which was used before to find the class of a value,
  • and all the operators (such as +,-,OR,etc.).

These examples for built-in functions can simply be called/used. However, some functions are not already built-in in the Python interpreter, for those a library with pre-coded algorithms first needs to be imported. An algorithm describes a step-by-step approach on how to solve a problem. However, in this tutorial, the terms functions and algorithms can be used interchangeably.

Self-created functions

How self-created functions can be defined and later on called will be looked at and as well why functions make coding more efficient.

Define a function

A function is structured as follows:

The abbreviation def stands for define. What comes after def is the name of the function(function_name). In parentheses (input) a parameter/placeholder is added for whatever value or variable will later on be plugged into the function. Then below this, the actual definition of the function follows which is referred to as "documentation string" or "doc string" for short. The doc string is used to give a brief explanation of what the function does. This allows other users (or the same user, if using the function later one) to get a quick summary of a function's purpose. The definition of the function is ended with return which gives back the output of the function.

In [16]:
def function_name(input):
    "documentation string"
    return output
In [17]:
# To look up the doc string of a function, enter the function name followed by ?
# The information will be displayed when you run the code in this cell

function_name?
In [18]:
# Another option is to use the built-in function help followed by the object in parentheses

help(function_name)
Help on function function_name in module __main__:

function_name(input)
    documentation string

In [19]:
# More complex functions require more documentation

help(print)
Help on built-in function print in module builtins:

print(...)
    print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
    
    Prints the values to a stream, or to sys.stdout by default.
    Optional keyword arguments:
    file:  a file-like object (stream); defaults to the current sys.stdout.
    sep:   string inserted between values, default a space.
    end:   string appended after the last value, default a newline.
    flush: whether to forcibly flush the stream.

Define a function which calculates the square of its input and call it square_function():

In [20]:
def square_function(x):
    "function that calculates the second power"
    result = x**2
    return result

Name a function

For naming a function the same rules like for naming a variable apply:

  • Use lowercase characters,
  • avoid non-letter characters (like !,&, %,,...),
  • underscore and numbers can be used, but not at the beginning of the name,
  • keywords (e.g. if, while, return,...) cannot be used as a name,
  • be as explicit as possible.

Call a function

To call or in other words to use a function, the name of the function together with the desired input in parentheses should be run:

In [21]:
square_function(5)
Out[21]:
25

Why functions are efficient

To illustrate why functions make programming more efficient, the square_function() is used to calculate the square of all numbers form 0 to 100:

In [ ]:
mylist = range(100)
result_list = []
i=0
for i in mylist:
    result_list.append(square_function(i))
print(result_list)

It can be observed that the square_function not only saves a lot of time, as it would have been cumbersome to calculate the square of every number individually, it also helped to avoid errors like missing out a number.

Here is a short guide helping to understand the code above as not all that is used has been treated yet:

  • range(x) creates a list of consecutive integeres from 0 to x,
  • for i in mylist is a loop which goes through every element in mylist (loops will be treated in a later tutorial),
  • result_list = [] means that the list of all results at the beginning is empty,
  • result_list.append(square_function(i)) means that every output of the square_function() is appended to the result_list,
  • print(result_list) shows the list of all results.

Difference between defining variables inside and outside of functions

There is one important feature of defining a variable on the top of your script. Such a variable is called global and can be accessed from anywhere in the script after the variable was defined. Here is an example of defining a global variable.

In [22]:
a = 2

def function(): 
    print(a)
    
function()
print(a)
2
2

When instead of only defining a variable at the beginning of a function, we define a variable inside the function, the relation and with it the priorities change. This can be seen in the following example.

In [23]:
a = 2

def function():
    a = 3
    print(a)
    
function()
print(a)
3
2

We have a built-in keyword in python that gives us more versatility in chosing when to use a globally defined variable or not. To use it, simply type global before the assigned variable name. Here is an example to illustrate the usage of the global keyword. The variable that we are referring to inside the function is now the global c, defined at the beginning of the script.

In [24]:
c = 20

def change_value(new_c): 
    global c 
    c = new_c
    
print(c)

change_value(40)

print(c)
20
40

There is another keyword that can be used when working with nested functions. We can use the keyword nonlocal when we want to avoid saving the variable locally, as in inside a function, but we want it saved a level higher. So instead of saving the variable inside the function, we save it at the beginning of the function, but also not globally, because there could be another function in between them. Let us first set up an example where we can illustrate the usage of nonlocal.

In [30]:
d = 20

def outer(): 
    d = 30
    def inner():
        d = 40
        print('from inner:', d)
    
    inner()
    print('from outer:', d)
    
outer()
print('gloablly:', d)
from inner: 40
from outer: 30
gloablly: 20

If we now use the nonlocal keyword in the inner function, we will see that the value of the variable 'e' we will be using in this particular function will be 40, as defined in the inner function. So that when calling the function outer, we will have 'e' defined as 40 and not 30.

In [29]:
e = 20 

def outer(): 
    e = 30
    def inner():
        nonlocal e
        e = 40
        print('from inner:', e)
        
    inner()
    print('from outer:', e)
    
outer()
print('globally:', e)
from inner: 40
from outer: 40
globally: 20

Now, if for example we want to refer to the global value of the variable in the inner function, without affecting the outer function, we could just set our variable f to global before defining it in the inner function. This way, the global variable will be changed to 40, but the definition of our variable in the outer function will not be affected.

In [28]:
f = 20

def outer(): 
    f = 30
    def inner(): 
        global f
        f = 40
        print('from inner:', f)
    
    inner()
    print('from outer:', f)
    
outer()
print('gloablly:', f)
from inner:  40
from outer:  30
gloablly: 40

Built-in functions

Although self-created functions can be defined in Python, whenever possible, built-in functions should be used as they are better designed than self-created functions. There exist two types of built-in functions in Python: Those within Python which can be simply called and those within libraries which first need to be imported.

Built-in functions within Python

For a start, built-in functions which form part of Python are looked at. These built-in functions can simply be called by using the name of the function and adding an input into its parentheses. Refer to the list below for common built-in functions (some might look familiar since we have encountered them in previous sections). This list is not exclusive, a more comprehensive list on built-in functions can be found here.

Function Description
abs() Returns the absolute value
append() Adds single elements to a list
count() Returns number of occurences of an element in a list
len() Returns length of a list
lower() Returns lowercase string
upper() Returns uppercase string
max() Returns largest element of a list
min() Returns smallest element of a list
print() Returns what is given within parantheses
return() Like print, used for defining functions
sum() Adds up items of a list
round() Returns rounded value
help() Shows information about function

Built-in functions within libraries

Secondly, we consider built-in functions for which first a library needs to be imported. A library contains one or more algorithms which are already pre-coded, in order that they can be called as soon as the library is imported. Note that the terms modules, packages and libraries are used interchangeably for the purposes of this tutorial.

How to import libraries

The following three sets of code import libraries into Python:

In [ ]:
import random #imports the entire library
from numba import jit #imports parts of a library
import numpy as np #imports a library and gives it a shorter name

How to install libraries

When running into an error whilst importing a library, it could be because the library has not been installed yet into your Python. When coding in Jupyter Notebook, some libraries are already installed and can simply be imported if needed, as for example numpy, scipy or random. Others need to be installed first. This is done by using pip. The pip is an installer program which is included in any later version than Python 3.4.

Remember from Tutorial 2 that any pip command can only be run outside Jupyter Notebook, meaning in the command line as follows (let us assume we want to install the library "theano"):

(base) C:\users\username pip install theano

Further information on how to install libraries can be found here.

Main libraries

Here is an overview on the most common libraries and packages in Python. Further libraries can be found here.

Library Description
Math
math Arithmetic functions
Data Science
numpy How to deal with data
random Generates random numbers
scipy Manipulating and visualizing data
numba Translates Python code to optimized and faster machine code
Machine-learning
scikit-learn Data mining and machine learning tasks
theano Uses GPU for intensive computation
TensorFlow Goolge framework for machine learning based projects
Web scraping and natural numbers processing
scrapy Web scraping tasks
NLTK Natural number processing (analyzing texts and finding correlations)
pattern Includes all web scraping and natural numbers processing libraries in one
Plotting and visualization
matplotlib Data visualization
seaborn Based on matplotlib library, to generate graphs in an easier way than matplotlib
bokeh Interactive, zoomable graphs. Based on modern web browser, uses javascript to render graph
ggplot Data visualization using grammar of graphics method (derivation of R's ggplot2)

Matplotlib

Discussing all the above libraries individually would go beyond the scope of this tutorial, however, the library matplotlib is introduced in more detailed as it is very useful for visualizing data.

Matplotlib is a Python 2D plotting library which can be used to visualize data as graphs, barcharts, histograms, timelines as well as further sorts of illustrations. This library is increasingly popular as it is considered a favorable alternative to the popular software MATLAB.

MATLAB (matrix laboratory) is a programming language developed by MathWorks for solving mathematical problems and providing graphical representation of the results. Matlab is mainly used in the fields of engineering, science and economics. The Python library Matplotlib together with the Python libraries numpy and scipy (see: Main libraries) is a good alternative to MATLAB as Python is free, whilst a license for MATLAB is rather expensive.

The goal is to plot the function: $y = 2x$. How this is achieved is looked at step-by-step:

  1. Generate the frame for the graph: Notice that after every step plt.show() is used so that you can see how the graph looks like so far
In [ ]:
# Import matplotlib:
import matplotlib.pyplot as plt 

# Generate the frame:
fig = plt.figure() # plots figure (can be thought of as area in which all needed for plot incl. axes, graph, labels is contained)
ax = plt.axes() # without axes the figure is not bounded and would not be displayed

#Show the graph:
plt.show()
  1. Define the length of the axes and label them:
In [ ]:
# Import matplotlib:
import matplotlib.pyplot as plt 

# Generate the frame:
fig = plt.figure()
ax = plt.axes() 


# Define length of axes and label them:
plt.axis([0,10, 0,20]) # the first two values define from where to where x-axis goes, the second two values for the y-axis
plt.grid() # adds a grid s.t. points on graph can be read off easier
plt.ylabel('Y-axis')
plt.xlabel('X-axis')

#Show the graph:
plt.show()
  1. Plot the function: Notice that for this step we also need to make use of the library numpy.
In [ ]:
# Import matplotlib and numpy:
import matplotlib.pyplot as plt 
import numpy as np

# Generate the frame:
fig = plt.figure()
ax = plt.axes() # without axes the figure cannot be displayed

# Define length of axes and label them:
plt.axis([0,10, 0,20]) # the first two values define from where to where x-axis goes, the second two values for the y-axis
plt.grid() # adds a grid, so that points on graph can be read off easier
plt.ylabel('Y-axis')
plt.xlabel('X-axis')

# Define x and y such that they adhere to the function and then plot them:
x = np.arange(0,10) # np.arange defines x as a range of evenly arranged inputs from 0 to 10
y = 2*x
ax.plot(x, y)

#Show the graph:
plt.show()
  1. Change linestyle and color of graph:
In [ ]:
# Import matplotlib and numpy:
import matplotlib.pyplot as plt 
import numpy as np

# Generate the frame:
fig = plt.figure()
ax = plt.axes() 

# Define length of axes and label them:
plt.axis([0,10, 0,20]) # the first two values define from where to where x-axis goes, the second two values for the y-axis
plt.grid() # adds a grid, so that points on graph can be read off easier
plt.ylabel('Y-axis')
plt.xlabel('X-axis')

# Define x and y such that they adhere to the function and then plot them:
x = np.arange(0,10) # np.arange defines x as a range of evenly arranged inputs from 0 to 10
y = 2*x
ax.plot(x, y, 'r-') # solid red
ax.plot(x, y+1, 'k:') # dotted black
ax.plot(x, y+2, 'g-.') # dash-dot green
ax.plot(x, y+3, 'c:') # dotted blue

#Show the graph:
plt.show()

This is one way of how to plot a function with matplotlib. For further insights into matplotlib go to Matplotlib.org or Python online handbook.

Encryption and Decryption

Encryption is an algorithm for transforming information in order to make it unintelligible. Decryption is an algorithm which transforms encrypted information so that it is intelligible again. Both encryption and decryption are socalled cryptographic algorithms. In most cases, for encryption and decryption two related algorithms are applied.

With most modern cryptography, the ability to keep encrypted information secret is not necessarily dependent on the cyptographic algorithm as this is widely known, but on a number called a key that must be used with the algorithm to produce an encrypted result or to decrypt previously encrypted information. Decryption with the correct key is simple. Decryption without the correct key is very difficult and in some cases impossible.

Encryption Decryption Source image: https://stackoverflow.com/questions/4948322/fundamental-difference-between-hashing-and-encryption-algorithms

Encryption

When encrypting a plain text, output and input of the encryption algorithm are defined as follows:

  • Input = A string of characters and spaces.
  • Output = A list of numbers and spaces.

To make an example on how to relate the above input to its output, the following encryption algorithm is defined:

  • Go through the elements in the string:
    • If the element is a space: Append it to the output list.
    • If the element is not a space:
      1. Find position in English alphabet,
      2. Square position,
      3. Append it to the output list.

The code below shows how to apply the encryption algorithm to encrypt a plain text.

In [32]:
import string

def encrypt(mystring): # as before with functions, we define the encryption algorithm and give it the name encrypt
    mystring = mystring.lower() # lower to transform all characters into lowercase
    mylist = [] # mylist is the output list, which is empty in the beginning

    for character in mystring: # for character in mystring is a loop (treated in later tutorial) which goes through all character within mystring
        if character.isspace(): # checks whether character under scrutiny is a space
            mylist.append(character) # If the character is a space: add it to mylist (output list)
        else: 
            mynumber = string.ascii_lowercase.index(character) # If character is not a space, find position in English alphabet
            # call this position mynumber
            mynumber = (mynumber)**2 # Square the position mynumber
            mylist.append(mynumber) # add it to the output list
    return mylist # return the output list

As an example, the plain text: "python is fun" is encrypted.

In [33]:
encrypt("python is fun")
Out[33]:
[225, 576, 361, 49, 196, 169, ' ', 64, 324, ' ', 25, 400, 169]

Notice that if you use any non-letter characters (like ?, . , !, ...), you will run into an error as these do not form part of the English alphabet.

5.2. Decryption

When decrypting an encrypted text, output and input are defined as follows:

  • Input = A list of numbers and spaces.
  • Output = A string of characters and spaces.

Notice that this is the reverse of the encryption, as with decryption we try to get back from the encrypted text to the plain text. Therefore, the decryption algorithm needs to be the reverse of what was used to encrypt the text:

  • Go through all elements in the list:
    • If the element is a space: Append it to the output string.
    • If the element is not a space:
      1. Take square root,
      2. Find what letter it is assigned to in the English alphabet,
      3. Append it to the output string.

The code below shows how to apply the decryption algorithm to decrypt an encrypted code:

In [34]:
import string

def decrypt(mylist):
    mystring = "" # as it is a string we use "" and not [] to show that there is nothing assigned yet to mystring
    
    for element in mylist: # as before: loop which goes through each element within mylist
        if element == " ": 
            mystring = mystring + element # if the element is a space, it gets added to the output list
        else: # if the element is a number,
            element = int(element**0.5) # the square root is taken of that element (to the power of 0.5)
            # then int() converts any floats to integers by rounding, as only for integers position in English alphabet can be found
            myletter = string.ascii_lowercase[element] # find associated letter in British alphabet, call it myletter
            mystring = mystring + myletter #add my letter to mystring
    return mystring # return the output string (mystring)

To check whether the decryption algorithm is correct, the encrypted text mylist is decrypted and it should return the plain text "python is fun".

In [35]:
mylist = [225, 576, 361, 49, 196, 169, ' ', 64, 324, ' ', 25, 400, 169]
decrypt(mylist) 
Out[35]:
'python is fun'

To double-check: If we encrypt a plain text and then decrypt it again, we should get the plain text:

In [36]:
decrypt(encrypt("python is a programming language"))
Out[36]:
'python is a programming language'

Now, the two functions decrypt() and encrypt() can be used to communicate secret messages. Make sure that the recipient is knowledgable about the algorithms that were applied in order to encrypt the secret message.