2.
Variables and operators
Variables are used to store values and to perform operations on them by means of operators.
2.1 Introduction
A variable is characterized by three features, its type, name, and value.
2.1.1 Basic variable types
Integers: positive/negative whole numbers (no decimal point)
Name in Python: int. Example: x = -5
Floating point numbers. Name: float.
Example: a = 2.05
Booleans: True, False. Name: bool.
Example: computation_finished = False
Strings: text composed of a sequence of characters enclosed by single or double quotes. Name: str.
Example: file_path = 'C:\\Documents\\doc1.pdf'
The built-in function type() displays the type of a variable:
In [1]: # Example: different variable types, usage of type() function.
x = -5
a = 2.05
computation_finished = False
file_path = 'C:\\Documents\\doc1.pdf'
type(x), type(a), type(computation_finished), type(file_path)
Out[1]: (int, float, bool, str)
2.1.2 Assignment of variables
= denotes the assignment operator, not the equality operator.
It assigns a specific value (or the value of a variable) on the right-hand side to a variable on the left.
In [2]: # Example: assignments.
x = 5 # The value 5 is assigned to a variable called x.
y = 3
y = y + x # The value of x is added to the value of y.
print(y)
print() is a built-in Python function that is often used to check the values of variables or to output intermediate/final results.
Multiple arguments possible, separated by commas.
The hash sign # is used for comments in the code.
It comments out everything until the end of the current line.
Simple, but very important observation:
A block of code is always executed line-by-line, starting from the first line.
→ first basic control structure for coding called sequence
In [3]: # Example: Boolean variables.
it_rains = True
it_hails = False
it_snows = False
has_precipitation = it_rains or it_hails or it_snows
print('Is there some precipitation today?', has_precipitation)
Is there some precipitation today? True
More about logical operators ( and , or , not ) in section 2.6.4.
Exercise 2.1:
Introduce some variables of different types by assigning values to them.
Perform some simple operations ( + , - , * , / as well as and , or , not ) on them.
Check the new values by printing the variables.
In [4]: # Solution to Exercise 2.1.
a = 5
b = -3
file_loaded = True
file_closed = False
print(a+b, -b, a-b, a*b, a/b, file_loaded and file_closed, file_loaded or file_closed, not file_loaded)
2 3 8 -15 -1.6666666666666667 False True False
2.2 Details about variables and their assignment
2.2.1 Variable names
Variable names are case-sensitive: e.g., a and A are different variables:
In [5]: # Example: case-sensitivity.
a = 'Variable names are case-sensitive!'
print(A)
----------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[5], line 4
1 # Example: case-sensitivity.
3 a = 'Variable names are case-sensitive!'
----> 4 print(A)
NameError: name 'A' is not defined
Allowed characters in variable names:
Letters
Digits (0, 1, ..., 9; except for first position)
Underscore sign _
Not allowed in variable names:
A digit as first character
Special characters, in particular empty space, dot . , hyphen/minus sign - , further arithmetic signs ( + , * etc.).
In [6]: # Example: allowed and not allowed patterns for variable names.
# Allowed:
my_address123 = '80801 Munich'
# Not allowed, producing an error message each:
2brothers = 'Thomas and Rolf'
variable value = 1.0
case-sensitive = True
Cell In[6], line 7
2brothers = 'Thomas and Rolf'
^
SyntaxError: invalid decimal literal
Exercise 2.2:
Introduce variables such that the expression case-sensitive does make sense.
What is the difference to the scenario above?
In [11]: # Solution to Exercise 2.2.
case = 7
sensitive = -0.4
new_variable = case-sensitive
# "case-sensitive" does not act as variable name,
# but as arithmetic expression for a variable assignment.
print(new_variable)
7.4
2.2.2 Naming conventions
Use simple, self-explanatory & specific names, ≤ 15 characters.
Good: velocity, num_channels = 72.6, 3
Sometimes good, usually bad: i , temp
Bad: tmp , var , a (too unspecific), uidfghb453 (confusing and typo-prone)
Very bad: Counter-intuitive names like normal_vector = 'https://www.google.de'
All lower-case and separated by underscores: pattern for variables and functions (except for constants and class names).
Good: customer_address , rolling_sum , delivery_date
Bad: customeraddress , SUM , deliveryDate
Global constants are written in upper-case separated by underscores: UPPER_VOLTAGE_THRESHOLD = 10.0
In case of functions, the What should be described, not the How.
Good: inner_product()
Bad: multiply_vector_components_and_sum_up()
2.2.3 Multiple assigments in one row
It is possible to assign multiple variables in one row. To do so, separate the single variables (and their assigned values) by commas:
In [8]: # Example: multiple assignments.
a, b, c = 1.0, -4, 'some text'
print(c, a)
some text 1.0
Note:
Parentheses () are possible but not mandatory.
Do not use multiple assignments by default, but only when it makes sense to group them together.
Good: (velocity, pressure, temperature) = (0.0, 250.0, -23.5)
Bad: web_address, x_coordinate = 'https://xyz.com', 12.3 (or the example above)
Exercise 2.3: Let's assume we want to assign certain values to quantities year of production, family name, number of errors occured, production week.
Assign meaningful names according to the naming conventions further above. (Invent some values for them.)
Group variables for assignment or assign them separately, whatever makes better sense.
In [10]: # Solution to Exercise 2.3.
prod_year, prod_week = 2023, 38
num_errors = 0
family_name = 'Müller'
2.3 Strings
2.3.1 Single vs. double quotes
For strings, single or double quotes can be used (but not mixed for start and end):
In [13]: # Example: single vs. double quotes for strings.
home_address = 'Würzburg' # First option: single quotes.
working_address = "Schweinfurt" # Second option: double quotes.
print(home_address, working_address)
#counter_example = 'Will not work!"
Würzburg Schweinfurt
Recommendation: By default use single quotes. When an apostrophe is part of the string, rewrite it as \' .
Only in some cases (see Section 2.4), double quotes are unavoidable.
\ is called escape character and changes the meaning of the subsequent character.
Their combination is called escape sequence. Such a sequence supports formatting or provides special characters (details in Section 2.3.4).
In [14]: # Example: single quote inside a single-quoted string.
message = 'It\'s fine to use single-quote strings.'
print(message)
It's fine to use single-quote strings.
Exercise 2.4: Introduce string variables with values
I'm excited about strings!
The referee replied, "Quiet, please.".
This 'can' become "tricky".
Print them.
In [12]: # Solution to Exercise 2.4.
string1 = 'I\'m excited about strings!'
string2 = 'The referee replied, "Quiet, please.".'
string3 = 'This \'can\' become "tricky".'
print(string1, string2, string3)
I'm excited about strings! The referee replied, "Quiet, please.". This 'can' become "tricky".
2.3.2 Concatenation of strings
Strings can be put together by the + operator:
In [15]: # Example: + operator for strings.
given_name = 'Tom'
family_name = 'Sawyer'
full_name = given_name + family_name
print(full_name)
TomSawyer
In [16]: # Example: adding an empty space between strings.
# Solution 1 by empty space string in between:
full_name = given_name + ' ' + family_name
print(full_name)
# "Solution" 2 by so-called trailing comma
# between arguments which creates a blank space:
print(given_name, family_name)
Tom Sawyer
Tom Sawyer
Repeated concatenation of a string can be achieved through the * operator:
In [17]: # Example: * operator for strings.
refrain = 'Highway to hell! '
song_text = 3 * refrain
print(song_text)
Highway to hell! Highway to hell! Highway to hell!
However: Strings and numbers (int, float) or Booleans cannot be concatenated directly:
In [18]: # Example: mixing different variable types.
name = 'Thomas'
age = 20
graduate = False
print('Has ' + name + ' (age ' + age + ') graduated? ' + graduate)
----------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[18], line 7
4 age = 20
5 graduate = False
----> 7 print('Has ' + name + ' (age ' + age + ') graduated? ' + graduate)
TypeError: can only concatenate str (not "int") to str
To do so, they must be converted to the same type by the built-in function str(). This is an example for a type conversion:
In [19]: # Example: cumbersome solution to mixing issue.
print('Has ' + name + ' (age ' + str(age) + ') graduated? ' + str(graduate))
Has Thomas (age 20) graduated? False
2.3.3 Python's f-strings
The construction above is ugly and hard to read due to the conversion commands and plus signs.
Since Python version 3.6, there is an elegant remedy: f-strings, indicated by a preceding f which stands for "formatting".
Inside the string, use braces ("curly brackets") {} for variable arguments:
In [20]: # Example: f-string.
question = f'Has {name} (age {age}) graduated? {graduate}'
print(question)
Has Thomas (age 20) graduated? False
As can be seen, type conversions are done automatically in f-strings (no str() necessary)!
When dealing with floats inside f-strings, the desired precision after the floating point can be chosen through :
In [21]: ## Example: formatting numbers in a f-string.
a = 0.123456789
b = -15000.3
message = f'First number: {a:.6f}. Second number: {b:.2e}'
# Here, "f" stands for float, "e" for exponential.
print(message)
First number: 0.123457. Second number: -1.50e+04
Question: What would have been the output if we had used {b:.0e} above?
Exercise 2.5: Convince yourself that f-strings provide correct rounding, e.g., by printing the number 0.49 with 1 resp. 0 digits after the floating point.
In [23]: # Solution to Exercise 2.5.
number = 0.49
message = f'Rounding {number} to 0 digits: {number:.0f}. And to 1 digit: {number:.1f}.'
print(message)
Rounding 0.49 to 0 digits: 0. And to 1 digit: 0.5.
2.3.4 r-strings
Backslashes in a string can lead to misinterpretation as escape sequence.
Raw strings, indicated by a preceding r , prevent that.
Note that f- and r-strings can be combined, e.g., new_path = fr'C:\new folder\{subfolder}' .
In [24]: # Example: situation when a r-string is advisable.
path = 'C:\new folder'
print(path)
C:
ew folder
In [25]: # Remedy: r-string or double backslash.
path1 = r'C:\new folder'
path2 = 'C:\\new folder'
print(path1, path2)
C:\new folder C:\new folder
List of escape sequences:
Output formatting:
\n (new line)
\t (horizontal tab)
\b (backspace)
\r (return)
Special characters:
\\ (backslash)
\' and \" (single/double quotes)
Exercise 2.6: (without support of Python)
What is the output of print('Schweinfurt has a\rtechnical university of applied sciences!\b') ?
What is the output of print(r'Würzburg has a\rtechnical university of applied sciences!\b') ?
Solution to Exercise 2.6.
technical university of applied sciences
Würzburg has a\rtechnical university of applied sciences!\b
2.3.5 Splitting strings
The "inverse" of concantenating can be achieved through the string method .split() :
It splits a string at the given argument into several pieces, returning a list of elements of type str .
(More about lists, indicated by brackets [] in Section 3.)
In [27]: # Example: the .split() method for strings.
names = 'Thomas, Susanne, Anita, Wolfgang'
single_names = names.split(', ')
print(single_names)
['Thomas', 'Susanne', 'Anita', 'Wolfgang']
Question: What would have happened if we had used single_names = names.split(',') above?
2.3.6 The in keyword
Another useful tool for strings is the in keyword:
string_1 in string_2 is a Boolean expression that returns True if string_1 is part of string_2 , and False otherwise.
In [28]: # Example: the "in" keyword for strings.
group_names = 'Paul, Armin, Susanne, Igor'
particular_name = 'Igor'
print(particular_name in group_names)
True
This turns out to be especially useful when dealing with file/folder names/paths.
2.4 Type conversions
Coming back to type conversions. The counterparts to str() are int(), float(), and bool():
In [29]: # Example: more type conversion commands.
number_as_string = '12'
print(51 + int(number_as_string))
integer_variable = 5
print(float(integer_variable))
package_has_arrived = 'True'
delivery_is_finished = -0.4 # bool(0) gives False, everything else True.
print(bool(package_has_arrived) and bool(delivery_is_finished))
63
5.0
True
In [30]: # Example: mixing ints, floats, and Booleans.
# This is fine:
print(int(number_as_string) + float(integer_variable))
# This is fine, too, since True gets interpreted as 1.
print(bool(delivery_is_finished) * integer_variable)
17.0
5
2.4.1 The input() function
Conversions from strings are, for example, necessary if the input() function is applied.
It reads in content that has been entered by the user interactively and returns this input as a string (!).
In [32]: # Example: input() function.
n = input('Please enter a number: ')
n = int(n) # Do not forget to convert n to an integer first!
m = n * 10
print(f'Your number times 10 equals to {m}.')
Please enter a number: 4
Your number times 10 equals to 40.
Question: How to fix this issue?
Exercise 2.7:
Write a short program where the input() function is used to read in a float.
Output this number up to 3 decimal places using the f-string formatting technique.
Test your program by some different inputs.
In [33]: # Solution to Exercise 2.7.
f = float(input('Please enter float: '))
print(f'Your number is {f:.3f}')
Please enter float: -0.12345
Your number is -0.123
2.5 Intermediate summary
No need to declare the variable types explicitly (as in other programming languages)
However, to run most operations between different types, they must be converted to the same type first.
str() , int() , float() , bool()
Exceptions: int/float operations; f-strings.
2.6 Operators
An operation is a function which takes input values, called arguments or operands, and returns a well-defined output.
The operation is often represented by a symbol called operator.
Simple example: addition/summation of two numbers a + b . Here, a and b are the operands, while + serves as operator.
2.6.1 Arithmetic operators
Arithmetic operators are
+ for addition
- for subtraction (two operands) or additive inversion (one)
* for multiplication
/ for division
// for floor division (rounded to nearest lower integer)
% for modulo operation
** for exponentiation.
In [34]: # Example: arithmetic operations.
a, b = 23, 10
print(f'a + b = {a + b}, a - b = {a - b}, -a = {-a}, a * b = {a * b}, ' +
f'a / b = {a / b}, a // b = {a // b}, a % b = {a % b}, and a**b = {a**b}.')
print(f'\nFloor division is of type {type(a // b)} for integers.')
x, y = 4.1, 0.7
print(f'For floats x = {x} and y = {y}, x // y = {x // y} is of type {type(x // y)}.')
a + b = 33, a - b = 13, -a = -23, a * b = 230, a / b = 2.3, a // b = 2, a % b = 3, and a**b = 41426511213649.
Floor division is of type <class 'int'> for integers.
For floats x = 4.1 and y = 0.7, x // y = 5.0 is of type <class 'float'>.
Remarks:
In the context of strings, + means concatenation and not addition.
The minus sign in -a is an example for an unary operator.
The result of the // operation is of type int for integer operands.
Exponentiation is not done via ^ as in many other languages/calculator apps.
a % b is pronounced "a modulo b" and yields the (signed) remainder when dividing a by b: a = m ⋅ b + a%b
In [35]: # Example: relation between // and %.
a, b = 23, 10
remainder = a % b # 23 % 10 gives 3.
factor_m = a // b # 23 // 10 gives 2.
print(f'a = {a}, while m * b + remainder = {factor_m * b + remainder}.')
a = 23, while m * b + remainder = 23.
Exercise 2.8: Introduce some numbers and strings and perform operations on them
using - in two different meanings
using + in two different meanings
using * in two different meanings.
In [37]: # Solution to Exercise 2.8.
a, b = 3, 5
name, message = 'Tom', 'hello'
print(a - b, -a)
print(a + b, name + message)
print(a * b, a * message)
-2 -3
8 Tomhello
15 hellohellohello
2.6.2 Compound assignment operators
Each arithmetic operator can be combined with an assignment operator = .
For instance, a *= 5 is short-hand notation for a = a * 5 .
(Note that such augmentations do not only exist for arithmetic operations, but also for bitwise and set-related ones. Details later.)
In [38]: # Example: compound assignment operations.
a = 2.5
print(f'Original value of a: {a}.')
a *= -6
print(f'a *= (-6): {a}.')
a **= 2
# Short for: a = a**2
print(f'a **= 2: {a}.')
Original value of a: 2.5.
a *= (-6): -15.0.
a **= 2: 225.0.
Note that there must be no space between arithmetic operator and = .
In particular, += and -= are called Python's increment operator and decrement operator, respectively.
The number to the right of it is called increment/decrement.
In [39]: # Example: decrement operator -=.
x = 20
x -= 5 # 5 is the decrement in this example.
print(f'x has now the value {x}.')
x has now the value 15.
Exercise 2.9: A = r
2
π
Let radius r = 2.0 and pi = 3.1415 .
Compute the area of the associated circle using two different compound assignment operations.
In [40]: # Solution to Exercise 2.9.
r, pi = 2.0, 3.1415
area = r
area **= 2
area *= pi
print(f'Formula: {r**2 * pi}. Area via compound assignments: {area}.')
Formula: 12.566. Area via compound assignments: 12.566.
2.6.3 Comparison operators
Comparison operators always work on two operands and return a Boolean value.
== is the equality operator.
!= is the inequality operator.
As expected, <= , < , >= , and > denote the "less/equal", "less", "greater/equal", and "greater" operators, respectively.
Remarks:
== and != can be used for integers, Booleans, and even strings.
Never use them for floats, since due to rounding errors or cancellation, results might be different than expected theoretically!
<= , < , >= , and > can be used for all basic variable types.
Do not confuse comparison operators with shift operators << , >> (see Chapter 10).
In [41]: # Example: comparison operators.
x, y, z = 0.17, -3.5, 44 # Note that z is an integer.
headline_today = 'Nvidia stocks rose!'
headline_tomorrow = 'Nvidia stocks fell!'
file_exists = True
folder_exists = False
print(x <= y, \
y > z, \
headline_today != headline_tomorrow, \
file_exists == folder_exists, \
headline_today > headline_tomorrow)
False False True False True
In [44]: # Example: comparing floats can give an unexpected result.
eps = 1.0e-16
one = 1.0
print(f'Left- and right-hand side are the same: {-one + (one + eps) == (-one + one) + eps}')
Left- and right-hand side are the same: False
Remember: = is the assignment operator, which is completely different from the equality operator == :
In [45]: # Example: assignment vs. equality operator.
x, y = -8000, 55.2
x = y # The value of y gets assigned to the variable x.
x == y # Not an assignment, but an expression returning a Boolean value.
# In this case "True", since x and y are equal after the command above.
# What is the outcome of line 11?
a = 10
b = a == 11
print(b, type(b))
False <class 'bool'>
Exercise 2.10: Figure out the value of b (without executing the cell).
2.6.4 Logical/Boolean operators
Named after George Boole (1815-1864).
and (binary operator representing logical conjunction)
or (binary operator representing logical disjunction)
not (unary operator representing logical negation)
In [46]: # Example: Boolean operators.
app_data_copied = True
paths_set = False
reboot_done = True
print(f'Installation started? {app_data_copied or paths_set}')
print(f"Reboot necessary? {not reboot_done}")
print(f'Problem occured during installation? {\
not (app_data_copied and paths_set)}')
Installation started? True
Reboot necessary? False
Problem occured during installation? True
Remarks:
Order of precedence is "not-and-or"
E.g., not True or True and not True gets grouped internally to (not True) or (True and (not True))
Advice: To avoid confusion, use parantheses to explicitely group longer expressions.
The exclusive or ("xor", "either this, or that, both not both") is not part of Python's syntax.
It can be mimicked by the construction
(a or b) and not (a and b) .
However, the bitwise xor is available, see a later chapter.
If one identifies True with 1 and False with 0, the mathematical representation of and , or , not are:
xy , x + y − xy , 1 − x , respectively.
Xor corresponds to x − 2xy + y .
Exercise 2.11:
Determine the Boolean value of the expression
not not False and not True or False or not False
by applying the "not-and-or" rule.
Confirm your result by printing the expression.
In [48]: # Solution to Exercise 2.11.
print(((not (not False)) and (not True)) or False or (not False))
True
2.7 Miscellaneous
2.7.1 Comments
A comment does not count as code and is only visible to the programmer. Comments can be created in two ways:
"Line-wise commenting":
Using the # symbol, the rest of the current line gets commented out as already mentioned.
"Block-wise commenting":
By ''' [text/code spanning multiple lines] ''' a whole block can be commented out.
Careful: Block-wise comments are convenient, but have potential side effects since block comments do not nest:
In [ ]: # Example: nested block comments.
'''a = 10
''' This block was already commented out,
for some reason.
x, y, z = 1, 2, 3 '''
print(a)'''
Exercise 2.12: Try to find a solution for the nesting problem above.
In [ ]: # Solution to Exercise 2.12.
'''a = 10
'.'' This block was already commented out,
for some reason.
x, y, z = 1, 2, 3 '.''
print(a)'''
Reasons for comments:
Explain code to others and to your future self
→ understandability & traceability
Structure code by forming blocks → readability
# Step 1: Get data. as first line of a block of code.
Document code. In industrial projects, this is standard and a contractual requirement.
Check impact of code lines by (un-)commenting them
→ useful for development & debugging
Leave warnings/reminders like
# TODO: add input check here.
Advice: Use comments frequently! And do not underestimate the role of comments!
It's a good programming habit to leave remarks and explanations for other people and for the future self.
2.7.2 Line break operator
The line break operator \ allows to break a long command into several lines.
It is very useful when dealing with multiple conditions or function arguments.
In [49]: # Example: \ operator.
a, b, c = -10, 22, -300
# Hard to read.
condition = (a > b and b <= c) or (a == c) or not(a > 0 and b < c)
# Structured by means of \ operator.
condition = (a > b and b <= c) or \
(a == c) or \
not(a > 0 and b < c)