Python: Basics#
This chapter assumes no prior knowledge of Python, and although not required, any experience with programming concepts or language will help.
Objectives#
Understand the standard Python datatypes such as
int
,float
,string
,list
,dict
,tuple
, etc.Perform arithmetic operations like
+
,-
,*
,**
on numeric values.Perform basic string operations and manipulations like
.lower()
,.split()
.Understand boolean values and comparison operators operations (
==
,!=
,>
, etc.) and boolean operators (and
,or
,not
).Assign, index, slice and subset values to and from tuples, lists, strings, and dictionaries.
Write a conditional statement with
if
,elif
andelse
.Identify code blocks by levels of indentation.
Explain the difference between mutable objects like a
list
and immutable objects like atuple
.
Basic Python Data Types#
A value is a piece of data that a computer program works with.
There are different types of values: 7
is an integer, 3.1415
is a float, and "Hello World!"
is a string.
A variable is a name that points to a value. In mathematics and statistics, we would write \(x=7\) where the variable \(x\) would point to the value 7.
In Python, we can use (almost) any characters, including unicodes, as a variable name as long as it starts with a letter or an underscore. However, it should not be a reserved word in Python such as for
, while
, class
, lambda
, etc. as these words encode language functionality in Python.
Warning
Python does not always protect the keywords we don’t want to overwrite!
We use the assignment operator =
to assign a value to a variable:
xy = 'hello'
Xy = 3 # case sensitive assigment
9x = 2 # SyntaxError: invalid decimal literal
x9 = 2
_x = 3.14 # ok, but special
if = 2 # Syntax error
Tip
See the Python 3 documentation for a summary of the standard built-in Python datatypes.
Some built-in Python data types#
English name |
Type name |
Type Category |
Description |
Example |
---|---|---|---|---|
integer |
|
Numeric Type |
positive/negative whole numbers |
|
floating point number |
|
Numeric Type |
real number in decimal form |
|
boolean |
|
Boolean Values |
true or false |
|
string |
|
Sequence Type |
text |
|
list |
|
Sequence Type |
a collection of objects - mutable & ordered |
|
tuple |
|
Sequence Type |
a collection of objects - immutable & ordered |
|
dictionary |
|
Mapping Type |
mapping of key-value pairs |
|
none |
|
Null Object |
represents no value |
|
There are many more built-in types in Python. We’ll cover this in the object programming part.
Numeric data types#
There are three distinct numeric types: integers
, floating point numbers
, and complex numbers
. We can determine the type of an object in Python using type()
. We can print the value of the object using print()
.
x = 7
type(x)
int
print(x)
7
In Jupyter/IPython (an interactive version of Python), the last line of a cell will automatically be printed to screen so we don’t actually need to explicitly call print()
.
x # Anything after the pound/hash symbol is a comment and will not be run
7
pi = 3.14159
pi
3.14159
type(pi)
float
0x9, 0xa, 0XF # Hex literals
(9, 10, 15)
Tip
Python (since version 3) also allows you to make large integers more readable by using _
as a separator.
e.g. 10_000
10_000, type(10_000)
(10000, int)
Arithmetic Operators#
Below is a table of the syntax for common arithmetic operations in Python:
Operator |
Description |
Example |
---|---|---|
|
addition |
|
|
subtraction |
|
|
multiplication |
|
|
division |
|
|
exponentiation |
|
|
integer division / floor division |
|
|
modulo |
|
Tip
(n // m) * m + (n % m) = n
Let’s have a go at applying these operators to numeric types and observe the results.
1 + 2 + 3 + 4 + 5 # add
15
2 * 3.14159 # multiply
6.28318
3.14159 ** 2 # exponent
9.869587728099999
Division may produce a different dtype
than expected, it will change int
to float
.
int_2 = 2
type(int_2)
int
int_2 / int_2, type(int_2 / int_2) # divison
(1.0, float)
But the syntax //
allows us to do “integer division” (aka “floor division”) and retain the int
data type, it always rounds down.
5 / 2
2.5
5 // 2 # "floor division" - always rounds down
2
5.1 // 1 # but conserves the most complex type (here float)
5.0
We refer to this as “integer division” or “floor division” because it’s like calling int
on the result of a division, which rounds down to the nearest integer, or “floors” the result.
int(5 / 2)
2
The %
“modulo” operator gives us the remainder after division.
100 % 2 # "100 mod 2", or the remainder when 100 is divided by 2
0
101 % 2 # "101 mod 2", or the remainder when 101 is divided by 2
1
100.5 % 2
0.5
Complex Numbers#
Complex numbers are built-in types in python, but intrinsically stored as two float types (real, imaginary) parts, respectively.
To create a complex number you can use the j
or J
character or the complex(.., ..)
function.
j # will not work
1J # or 1j will
2.+3j, 2-3J, complex(1,2)
((2+3j), (2-3j), (1+2j))
(2.+3j).real, (2+3j).imag
(2.0, 3.0)
None#
NoneType
is its own type in Python. It only has one possible value, None
- it represents an object with no value. We’ll see it again in a later chapter.
x = None
print(x)
None
type(x)
NoneType
Strings#
Python stores any series of characters (or text) as a data type called a string
. There are not difference in python whether the string is a single character or a list of characters (unlike C for instance.).
We write strings as any characters enclosed with either:
single quotes, e.g.,
'Hello'
double quotes, e.g.,
"Goodbye"
There’s no difference between the single or double quotes in Python. There are cases where having both is useful.
Multiline string exists as well and requires triple single/double quotes. These are used for function documentation (more on that later), e.g. """This 'function' does something cool."""
.
name = "Alice"
name
'Alice'
type(name)
str
a_longer_text = "If a string contains a quotation or apostrophe, we'd combine single and double quotes to define it."
a_longer_text
"If a string contains a quotation or apostrophe, we'd combine single and double quotes to define it."
quote = 'Donald Knuth: "Premature optimization is the root of all evil."'
quote
'Donald Knuth: "Premature optimization is the root of all evil."'
Boolean#
The Boolean (bool
) type has two values: True
and False
.
the_truth = True
the_truth
True
type(the_truth)
bool
lies = False
lies
False
type(lies)
bool
Comparison Operators#
We can compare objects using comparison operators, and we’ll get back a Boolean result:
Operator |
Description |
---|---|
|
is |
|
is |
|
is |
|
is |
|
is |
|
is |
|
is |
2 < 3
True
"Hello World!" == "Traditional entry example!"
False
"Hello World" == "hello world"
False
2 != "2"
True
2 == 2.0 # value comparison not limited by types
True
Python also offers syntax close to human language, for instance you can write
1 < 2 <= 3 # instead of (1<x) and (x<=3)
True
3 < 2 <= 1, 1 < 0.5 >= 0
(False, False)
Boolean Operators#
We also have so-called “boolean operators” which also evaluates to either True
or False
:
Operator |
Description |
---|---|
|
are |
|
is at least one of |
|
is |
True and True
True
True and False
False
True or False
True
False or False
False
("Python 2" != "Python 3") and (2 <= 3)
True
True, not True, not not True
(True, False, True)
Special float values: NaN, Infinity#
In python, you also have built-in NaN and Infinity values. float('NaN')
and float('Infinity')
float('NaN'), float('nan'), float('infinity'), float('Inf') # case insensitive
(nan, nan, inf, inf)
Don’t be confused by their behavior with arithmetic and comparison operators
nan = float('NaN')
nan < nan, nan == nan, nan ** 2, nan + 1, nan + 1 == nan
(False, False, nan, nan, False)
inf = float('Infinity')
-inf < inf, inf == inf ** 2
(True, True)
Bitwise operators#
Python also has bitwise operators like &
and |
. Bitwise operators literally compare the bits of two integers.
operation |
operator |
example |
---|---|---|
AND |
|
|
OR |
` |
` |
XOR |
|
|
bitwise complement |
|
|
bitshift left |
|
|
bitshift right |
|
|
Casting#
Sometimes we need to explicitly cast a value from one type to another. We can do this using functions like str()
, int()
, and float()
. Python tries to do the conversion, or throws an error if it can’t.
x = 5.0
type(x)
float
x = int(5.0)
x
5
type(x)
int
x = str(5.0)
x
'5.0'
type(x)
str
str(5.0) == 5.0
False
int(5.3)
5
float("hello")
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[60], line 1
----> 1 float("hello")
ValueError: could not convert string to float: 'hello'
Variable manipulation#
Python variable assignments are mostly standard, as the previous example shows. But there are some points to remember:
x = 2 # Assigns variable
x + 3 # Uses variable
y = x + 3 # Creates a new variable
x = x + 1 # Assigns a new value
Note
x++
does not exist in Python. Instead, you need to use x += 1
Some stunts of python in variable manipulation
x, y = 2, 3
print(x, y)
2 3
x, y = y, x
x, y # no need for intermediate variable!
(3, 2)
x = y = z = 0
print(x, y, z)
0 0 0
Warning
x = y = z = 0
instanciate all these variables to the value 0. But in some cases that we will discuss later, they all point to the same memory location, i.e. share the same value instead of being independent variables.
Sequences: Lists, Tuples, strings, and sets#
Lists and tuples#
We have seen string types above. These are sequences of characters defined with single, double or triple quotes.
Lists and tuples allow us to store multiple elements in a single object. These elements are ordered and they can be of different types.
Lists are defined with square brackets []
.
my_list = ["numbers", 1, "TWO", 3.01, complex(4, 5), [True, False], float('inf')]
my_list
['numbers', 1, 'TWO', 3.01, (4+5j), [True, False], inf]
type(my_list)
list
Lists can hold any datatype, and even other lists. This is similar to a N-dimensional array, but with potentially different lengths and types.
another_list = [[1, 2, 3], [4, 5, 6], [7, 8]]
another_list
[[1, 2, 3], [4, 5, 6], [7, 8]]
You can get the length of the list with the function len()
:
len(my_list), len(another_list)
(7, 3)
Tuples look similar to lists but have a key difference: they are immutable. That means they can’t be modified after creation. Lists are mutable and we can assign new values to any element.
Tuples are defined with parentheses ()
.
my_tuple = ("numbers", 1, "TWO", 3.01, complex(4, 5), [True, False], float('inf'))
my_tuple
('numbers', 1, 'TWO', 3.01, (4+5j), [True, False], inf)
type(my_tuple), len(my_tuple)
(tuple, 7)
Tip
Have you noticed that when we display a, b
, as in the previous line, python displays a tuple (value_a, value_b)
?
Before we can explicit the immutable state of a tuple, we need to learn how we get and set individual elements.
Indexing and Slicing Sequences#
We can access values inside a list, tuple, or string using square bracket syntax. Python uses zero-based indexing, which means the first element of the list is in position 0, not position 1.
my_list
['numbers', 1, 'TWO', 3.01, (4+5j), [True, False], inf]
my_list[0], my_list[3]
('numbers', 3.01)
In python, list indexing starts from 0 (similar to many programming languages but Fortan for instance, starting at 1). Similarly to Java for instance, Python checks that you do not try to access an element outside the sequence.
my_list[27]
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
Cell In[72], line 1
----> 1 my_list[27]
IndexError: list index out of range
Something new from Python is that we can use negative indices to count backwards from the end of the list.
my_list[-1], my_list[-1] == my_list[len(my_list) - 1], my_list[-4]
(inf, True, 3.01)
If we want to get a subset of a list, we can slice it using the colon :
.
If L
is a list, the expression L [ start : stop : step ]
returns the portion of the list from index start
to index stop
, at a step size step
.
my_list[1:3]
[1, 'TWO']
Note from the above that the start of the slice is inclusive and the end is exclusive. So my_list[1:3]
fetches elements 1 and 2, but not 3.

Fig. 2 The slicing operation uses the element position which preceed the value. So that L[2: 7]
does not include the item at index 7 ‘h’.
Image credit learning by examples#
Strings behave the same as lists and tuples when it comes to indexing and slicing. Remember, we think of them as a sequence of characters.
abc = "abcdefghijklmnopqrstuvwxyz"
abc[0], abc[-1], abc[22: 10: -5], abc[:-5], abc[20:]
('a', 'z', 'wrm', 'abcdefghijklmnopqrstu', 'uvwxyz')
Tip
Note that slicing steps can be negative. You can reverse a sequence by my_list[::-1]
. (or use the more flexible function reversed()
)
List methods#
A list is an object and it has associated functions, called methods for interacting with its data.
We will come back to the object and method vocabulary in the object oriented programming part. For now, let’s identify a method as a function that we access using a period .
after a variable name.
For example, my_list.append(item)
appends an item to the end of the list called my_list
.
lst = [1, 2, 3]
lst
[1, 2, 3]
len(lst)
3
lst.append(4)
lst
[1, 2, 3, 4]
lst.extend([5, 6, 7])
lst
[1, 2, 3, 4, 5, 6, 7]
Tip
You can see the documentation for more list methods.
Mutable vs. Immutable Types#
Strings and tuples are immutable types, that means read only variables once they are created. In comparison, lists are mutable, we can assign new values to any element. This is the main difference between lists and tuples (there are other implications behind the scenes).
cities_list = ["Paris", "Madrid", "Rome"]
cities_list
['Paris', 'Madrid', 'Rome']
cities_list[0] = 'Berlin'
cities_list
['Berlin', 'Madrid', 'Rome']
cities_tuple = ("Paris", "Madrid", "Rome")
cities_tuple
('Paris', 'Madrid', 'Rome')
cities_tuple[0] = "Berlin"
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[83], line 1
----> 1 cities_tuple[0] = "Berlin"
TypeError: 'tuple' object does not support item assignment
Same goes for strings. Once defined we cannot modifiy the characters of the string.
cities_tuple[0][1] = 'A'
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[84], line 1
----> 1 cities_tuple[0][1] = 'A'
TypeError: 'str' object does not support item assignment
But tuples can store pointers to mutable objects
x = (cities_list, 'Berlin')
x
(['Berlin', 'Madrid', 'Rome'], 'Berlin')
x[0][0] = 'Paris'
x
(['Paris', 'Madrid', 'Rome'], 'Berlin')
Sets#
set
is a particular built-in sequence in Python. It stores un-ordered and unique items.
Sets are “mutable” as you can add or remove elements, but they do not support indexing.
You can define a set by a sequence of items between {}
or with the set()
function.
s = {2, 1, 3}
s, type(s)
({1, 2, 3}, set)
{1, 2, 3} == {3, 2, 1} == {2, 1, 3} == {3, 1, 2}
True
[1, 2, 3] == [3, 2, 1]
False
You can add elements using the associated method .add()
s.add(2) # does nothing as 2 already exists
s
{1, 2, 3}
s.add(5) # But this adds it
s
{1, 2, 3, 5}
s.remove(5) # removes the item with value 5, not the 5th element.
s
{1, 2, 3}
s[0]
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[93], line 1
----> 1 s[0]
TypeError: 'set' object is not subscriptable
Arithmetic operators on sequences#
There are possible operations on sequences but avoid them if possible. These are not optimized for memory and speed. The examples below are mostly traps I’ve seen people falling into, especially when confusing sequences with arrays.
[1, 2, 3] + [4, 5, 6]
[1, 2, 3, 4, 5, 6]
The sum of sequences creates a new sequence of the same type with a shallow copy of the elements. This may generate a lot of memory overhead.
(1, 2) * 4
(1, 2, 1, 2, 1, 2, 1, 2)
Product operation generates repeated sequence copies. This could become expensive mistakes.
[1, 2] / 4
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[96], line 1
----> 1 [1, 2] / 4
TypeError: unsupported operand type(s) for /: 'list' and 'int'
Not all operators work on sequences. Prefer their methods, which are safer and optimized.
Warning
Arithmetic operations on sequences are often because of a confusion with manipulating arrays.
More on python strings#
String Methods#
Strings are immutable sequences of characters. There are various commonly used methods in Python, and too many to list them all here. Check out the documentation.
Some examples of frquently used methods.
all_caps = "HELLO WORLD!"
all_caps
'HELLO WORLD!'
all_caps.lower(), all_caps
('hello world!', 'HELLO WORLD!')
Note that the method lower doesn’t change the original string but rather returns a new one.
all_caps.split()
['HELLO', 'WORLD!']
all_caps.count("L")
3
One can explicitly cast a string to a list:
list(all_caps)
['H', 'E', 'L', 'L', 'O', ' ', 'W', 'O', 'R', 'L', 'D', '!']
"*".join(list(all_caps)) # which can join multiple strings
'H*E*L*L*O* *W*O*R*L*D*!'
"*".join(all_caps)
'H*E*L*L*O* *W*O*R*L*D*!'
Warning
a string is a sequence of strings (individual characters). Hence "*".join(list(all_caps)) == "*".join(all_caps)
We can also chain multiple methods together (more on this when we get to NumPy and Pandas in later chapters):
"".join(all_caps).lower().split(" ")
['hello', 'world!']
String formatting .format()
, f-strings#
String outputs is a big part of our scientific work. Wheter it is to report about a single value or a list of values, formatting the output of a code is important.
Python has multiple ways to format strings nicely. Have a look at the online documentation for details.
name = 'Alice'
takeoff = 'Berlin'
landing = 'New York'
duration_in_hours = 9.2
The manual way, which can rapidly become hard to read and cumbersome
print(name +"'s flight from " + takeoff + " to " + landing + " took " + str(duration_in_hours) + " hours")
Alice's flight from Berlin to New York took 9.2 hours
The str.format()
method, uses {
and }
to mark where a variable will be substituted and can provide detailed formatting directives.
print("{0:s}'s flight from {1:s} to {2:s} took {3:f} hours.".format(name, takeoff, landing, duration_in_hours))
Alice's flight from Berlin to New York took 9.200000 hours.
# works also with names
print(
"{name:s}'s flight from {takeoff:s} to {landing:s} took {duration:0.1f} hours.".format(
name=name, takeoff=takeoff, landing=landing, duration=duration_in_hours)
)
Alice's flight from Berlin to New York took 9.2 hours.
Positional and keyword arguments can be arbitrarily combined:
print('{0:s}: "This {food} is {adjective}."'.format(name,
food='spam', adjective='absolutely horrible'))
Alice: "This spam is absolutely horrible."
More powerful, if you have a really long format string, you can reference the variables to be formatted by name instead of by position. This can be done by simply passing the dict and using square brackets []
to access the keys.
table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678}
print('Jack: {0[Jack]:d}; Sjoerd: {0[Sjoerd]:d}; '
'Dcab: {0[Dcab]:d}'.format(table))
Jack: 4098; Sjoerd: 4127; Dcab: 8637678
This opens a lot of possibilities as you can access variable attributes in the formatting instructions.
Note
The %
operator (modulo) can also be used for string formatting as in other languages. This is the “old ways” called string interpolation or printf
-style, i.e. "string" % values
. For example:
print('The value of pi is approximately %5.3f.' % 3.1415926535)
which return The value of pi is approximately 3.142.
This formatting definition is not recommended as it removes the readibility of your code. Prefer the {}
and str.format()
method instead.
A new powerful manner to format string is to use formatted string literals or f-string. These strings begin with f or F before the opening quotation mark (or triple quotation mark). Inside this string, you can write a Python expression between { and } characters that can refer to variables or literal values in the current running scope. (see online documentation)
year = 2016
event = 'Referendum'
yes_votes = 42_572_654
no_votes = 43_132_495
percentage = yes_votes / (yes_votes + no_votes)
print(f"""Results of the {year} {event}:
yes: {yes_votes:,d} ({percentage:2.2%}),
no: {no_votes:,d} ({(no_votes / (yes_votes + no_votes)):2.2%})
""")
Results of the 2016 Referendum:
yes: 42,572,654 (49.67%),
no: 43,132,495 (50.33%)
Note
In the formatting examples above, the notation after the colon in my curly braces is for formatting. For example, :.2f
means, print this variable with 2 decimal places. See format code options here.
Dictionaries#
A dictionary is a mapping between key-values pairs and we define one using curly-brackets:
a = dict(one=1, two=2, three=3)
b = {'one': 1, 'two': 2, 'three': 3}
c = dict(zip(['one', 'two', 'three'], [1, 2, 3]))
d = dict([('two', 2), ('one', 1), ('three', 3)])
e = dict({'three': 3, 'one': 1, 'two': 2})
f = dict({'one': 1, 'three': 3}, two=2)
a == b == c == d == e == f
True
We can access a specific field of a dictionary with square brackets:
a['one'], b['three']
(1, 3)
Dictionaries are mutable objects, which means we can edit and add/remove values
a["new"] = 5
a['one'] = 'one'
a
{'one': 'one', 'two': 2, 'three': 3, 'new': 5}
We can also delete fields entirely:
del a["new"]
a
{'one': 'one', 'two': 2, 'three': 3}
Similarly to a list, a dictionary can store any types of values and the indexing uses keys instead of only integers.
{27: 'twenty-seven',
'one': 1,
'lst': [1, 2, 3],
(1,2): 45}
{27: 'twenty-seven', 'one': 1, 'lst': [1, 2, 3], (1, 2): 45}
Keys can be almost any type of object. In the example above, we use the tuple (1,2)
as a key. We could not use a list.
{27: 'twenty-seven',
'one': 1,
'lst': [1, 2, 3],
[1,2]: 45}
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[117], line 1
----> 1 {27: 'twenty-seven',
2 'one': 1,
3 'lst': [1, 2, 3],
4 [1,2]: 45}
TypeError: unhashable type: 'list'
If you try to access a key that does not exist, you get an exception
a[10]
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
Cell In[118], line 1
----> 1 a[10]
KeyError: 10
Try to check before,
10 in a, 'one' in a
(False, True)
or get a default value instead
a.get(10, 'ten')
'ten'
a['bacon'] = 13 # adds an item
del a['bacon'] # removes it.
Digression around variable assignement: avoiding a common trap!#
In C/C++ language for instance, the declaration of a variable sets a place in memory to use
int x, y; // initialized variables with "random" values
x = 2; // the memory location of x contains 2, y remains undetermined.
x = 3; // at the x memory location we get 3, y remains undetermined
y = x; // at the y memory location we copied the value from the x location, which is now 3.
In python, it is different. Any variable name points to a value which is allocated in memory.
planet = "Pluto" # planet points to an object of type `str` in memory containing "Pluto".
planet = "Tiamat" # planet now points to a different object of type `str` in memory containing "Tiamat".
# Because "Pluto" is not referenced by other names, Python will tag it for deletion (garbage)
legend = planet # "legend" points to the same object string "Tiamat" in memory.
del planet # will remove the name but legend persists
del legend # will remove the name and tag "Tiamat" in memory as garbage.
Warning
the garbage collection in Python is not immediate unless manually trigged. This is important to keep in mind when codes have strict memory limitations.
l = [1,2,3]
m = [1,2,3] # l and m are different objects
l == m # Equality (of values) tested with ==
True
l is m # Identity (of objects) tested with is
False
l[0] = 42
print(l)
print(m)
[42, 2, 3]
[1, 2, 3]
l = [1,2,3]
m = l
l == m, l is m
(True, True)
l[0] = 42
l, m
([42, 2, 3], [42, 2, 3])
The variable assignement in Python can be leading to some confusing results. By default, Python will try to avoid copying values (unless atomic, i.e. numerical literals). Explicitly copying a variable may be needed with copy.copy()
or copy.deepcopy()
(documentation).
Conditionals#
From the examples before, there are times we would like to execute one or another operation depending on the state of some variables. Conditional statements allow us to write codes that have conditional behaviors.
name = "Santa"
if name.lower() == "alice":
print(f"{name}! That's my name too!")
elif name.lower() == "santa":
print("That's a funny name.")
else:
print(f"Hello {name}! That's a cool name!")
print(f"Nice to meet you, {name}.")
That's a funny name.
Nice to meet you, Santa.
Conditional coding in python uses
if
,elif
, andelse
keywordsthe colon
:
ends each conditional expression,a superior indentation defines code blocks,
if
statements don’t necessarily needelif
orelse
,elif
lets us check several conditions until one works,else
evaluates a default block if other tested conditions areFalse
the end of the entire
if
statement is where the indentation returns to the same level as the firstif
keyword
Tip
Indentation defines a block of instructions in Python
The top-level must not be indented. It does not matter how much blanks you use, but:
it must be uniform within each block
Most people use 4 blanks per level but tabs work too (but python does not accept mixing tabs and spaces for that)
You can look at the styleguide (PEP8) by Guido van Rossum, Barry Warsaw, and Nick Coghlan for good code styling practices.
Inline if/else#
We can write simple if
statements inline, i.e., in a single line.
lst = ['a', 'list', 'of', 'values']
if len(lst) > 10:
x = "probably a sentence."
else:
x = "seems only a few words"
x
'seems only a few words'
x = "probably a sentence" if len(lst) > 10 else "seems only a few words"
x
'seems only a few words'
Shortcuts#
Python supports a concept known as “short-circuiting”. This is the automatic stop of evaluating boolean operation if the truth value of expression has already been determined.
undef_variable # not defined
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[131], line 1
----> 1 undef_variable # not defined
NameError: name 'undef_variable' is not defined
True or undef_variable
True
True and undef_variable
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[133], line 1
----> 1 True and undef_variable
NameError: name 'undef_variable' is not defined
not (False and undef_variable)
True
Expression |
Result |
Detail |
---|---|---|
A or B |
If A is |
B only executed if A is |
A and B |
If A is |
B only executed if A is |
Loops#
The while statement#
The while
statement is a loop that runs until a condition evaluates to False
.
The while
loop in Python is a control flow statement that executes a block of code repeatedly until a given condition is evaluated to be False
.
Each iteration evaluates the condition first before executing the code in the loop body. Once the condition evaluates to False, the execution of the loop is terminated. The syntax for a while loop is as follows:
while condition:
# loop body
x = 0
while x <= 5: # Bool. expr.
print (x, x**2) # Indentation
x += 1 # update state
print(x) # Unindented again
0 0
1 1
2 4
3 9
4 16
5 25
6
How much is the smallest / largest positive float
Use a while loop, compare to 0 and float(‘inf’) and find an approximative answer
How much is the smallest / largest positive float
Use a while loop, compare to 0 and float(‘inf’) and find an approximative answer
The following compares the value of x to 0 and inf, respectively. The while loop stops when they become equal for the computer’s float precison.
val = x = 1.
while x > 0:
val = x
x /= 2.
print(x)
5e-324
val = x = 2 ** 32.
while x != float('inf'):
val = x
x *= 2.
print(val)
8.98846567431158e+307
Strictly, we found the actual smallest and highest values to a factor of 2. We would need to adjust the multiplicative factor to find it with more precision.
import sys
print("Strictly speaking")
print("highest: ", sys.float_info.max, "smallest: ", sys.float_info.min)
Strictly speaking
highest: 1.7976931348623157e+308 smallest: 2.2250738585072014e-308
We did not see imports yet.
How precise is your installation?
Add smaller and smaller numbers to 1 while comparing the sum to 1
How precise is your installation?
Add smaller and smaller numbers to 1 while comparing the sum to 1
The following compares the value of x to 0 and inf, respectively. The while loop stops when they become equal for the computer’s float precison.
val = x = 1.
while 1. + x > 1.:
val = x
x /= 2.
print x
1.1102230246251565e-16
Strictly, we found the actual smallest and highest values to a factor of 2. We would need to adjust the multiplicative factor to find it with more precision.
import sys
print("Strictly speaking")
print("precision: ", sys.float_info.epsilon)
Strictly speaking
precision: 2.220446049250313e-16
We did not see imports yet.
For loops#
A for
loop in Python is a type of loop that iterates over a sequence of values, such as a list
, tuple
, or string
as see above.
The for loop has two parts: the initialization and the condition, where the loop starts and the condition to meet to execute the code (similarly to while
)
When the condition is met, the loop stops and the code after the loop is executed. A for loop is very useful when you need to repeat a set of instructions a certain number of times. It is also helpful in iterating efficiently through sequences.
For example, you can use a for loop to print out each character in a string:
for char in "Hello World":
print(char)
for color in ['red', 'green', 'blue', 'yellow', 'cyan']:
print(color)
red
green
blue
yellow
cyan
The range
function#
The range(start, stop, step)
function generates a sequence of values which range from start
to stop-1
with a step of step
.
range(10)
range(0, 10)
list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
list(range(0, 10)) == list(range(10))
True
for k in range(10, 16, 2):
print(k)
10
12
14
Inline for loop#
Sometimes we can write a for instruction inline, i.e. more condensed.
result = []
for i in range(10):
if i % 2:
result.append(i)
result
[1, 3, 5, 7, 9]
This can be condensed into
[i for i in range(10) if i % 2]
[1, 3, 5, 7, 9]
We will come back to this particular syntax, but note that we obtain a list with the entries we selected. In this case, Python is smart and optimizes the memory allocations.
{warning} Inline code does not always make your code readable. Readability is a primary goal for Python
Break Statement in loops#
The Python break
statement is used to exit from a loop immediately after a certain condition is met.
for color in ['red', 'green', 'blue', 'yellow', 'cyan']:
print(color)
if color == 'green':
break
red
green
In this example, the condition of color=='green'
happens and the loop stops (we do not print the other colors).
Bracket the value 2.4 with elements from [1, 1.41, 1.65, 1.73, 2.24, 2.65, 2.71, 3.14]
Either a for loop or while would work
Bracket the value 2.4 with elements from [1, 1.41, 1.65, 1.73, 2.24, 2.65, 2.71, 3.14]
Either a for loop or while would work
for
loop solution
value = 2.4
lst = [1, 1.41, 1.65, 1.73, 2.24, 2.65, 2.71, 3.14]
for i in range(len(lst) -1 ):
if lst[i] <= value < lst[i+1]:
break
print(f'{lst[i]} <= {value:f} < {lst[i+1]}, found at i={i}')
2.24 <= 2.4 < 2.65, found at i=4
while
loop solution
value = 2.4
lst = [1, 1.41, 1.65, 1.73, 2.24, 2.65, 2.71, 3.14]
i = 0
while not (lst[i] <= value < lst[i+1]):
i += 1
print(f'{lst[i]} <= {value:f} < {lst[i+1]}, found at i={i}')
2.24 <= 2.4 < 2.65, found at i=4
The continue
instruction in loops#
The function of the continue
statement is to skip the current iteration of a loop and continue with the next one.
for color in ['red', 'green', 'blue', 'yellow', 'cyan']:
if color == 'green':
continue
print(color)
red
blue
yellow
cyan
The green
value does not appear. We skipped this iteration.
Else
in loops#
Python enables an else
clause at the end of a for
/while
loop. The else
code runs if the loop terminates naturally.
for color in ['red', 'green', 'blue', 'yellow', 'cyan']:
if color == 'green':
continue
print(color)
else:
print('--[Done]--')
red
blue
yellow
cyan
--[Done]--
Which is different from
for color in ['red', 'green', 'blue', 'yellow', 'cyan']:
if color == 'green':
break
print(color)
else:
print('--[Done]--')
red
Note that the else
clause did not run.
It is similar for while
loops.
i = 0
lst = list(range(10))
while lst[i] < 3:
print(lst[i])
i += 1
else:
print('--[done]--')
0
1
2
--[done]--
enumerate
, accessing the iteration index in for Loops#
Sometimes you need to iterate over the indices in a sequence. We use the enumerate()
function.
for i, color in enumerate(['red', 'blue', 'green', 'yellow'], 1):
print(i, color)
1 red
2 blue
3 green
4 yellow
zip
, looping through multiple sequences in parallel#
The zip()
function in Python takes in sequences (can be zero or more) and returns a new sequence which contains tuples of elements taken from each sequence.
The i-th tuple contains the i-th element from each of the arguments. The sequence stops when the shortest input is exhausted.
This function is used to map the similar index of multiple containers so that they can be used just using as single entity.
for k, v in zip(range(3), ['red', 'blue', 'green', 'yellow']):
print(k, v)
0 red
1 blue
2 green
In this example, the first sequence contains only 3 elements. zip
stopped after the third iteration.
zip
is very useful to avoid manipulating indexes manually. You can focus on the elements directly.