python_101 12/09/23, 10:19 AM
Python 101
This is an optional notebook to get you up to speed with Python in case you are new to
Python or need a refresher. The material here is a crash course in Python; I highly
recommend the official Python tutorial for a deeper dive. Consider reading this page in
the Python docs for background on Python and bookmarking the glossary.
Basic data types
Numbers
Numbers in Python can be represented as integers (e.g. 5 ) or floats (e.g. 5.0 ). We can
perform operations on them:
In [ ]:
5 + 6
11
Out[ ]:
In [ ]:
2.5 / 3
0.8333333333333334
Out[ ]:
Booleans
We can check for equality giving us a Boolean:
In [ ]:
5 == 6
False
Out[ ]:
In [ ]:
5 < 6
True
Out[ ]:
These statements can be combined with logical operators: not , and , or
In [ ]:
(5 < 6) and not (5 == 6)
True
Out[ ]:
about:srcdoc Page 1 of 17
python_101 12/09/23, 10:19 AM
In [ ]:
False or True
True
Out[ ]:
In [ ]:
True or False
True
Out[ ]:
Strings
Using strings, we can handle text in Python. These values must be surrounded in quotes
— single ( '...' ) is the standard, but double ( "..." ) works as well:
In [ ]:
'hello'
'hello'
Out[ ]:
We can also perform operations on strings. For example, we can see how long it is with
len() :
In [ ]:
len('hello')
5
Out[ ]:
We can select parts of the string by specifying the index. Note that in Python the 1st
character is at index 0:
In [ ]:
'hello'[0]
'h'
Out[ ]:
We can concatentate strings with + :
In [ ]:
'hello' + ' ' + 'world'
'hello world'
Out[ ]:
We can check if characters are in the string with the in operator:
In [ ]:
'h' in 'hello'
True
Out[ ]:
about:srcdoc Page 2 of 17
python_101 12/09/23, 10:19 AM
Variables
Notice that just typing text causes an error. Errors in Python attempt to clue us in to what
went wrong with our code. In this case, we have a NameError exception which tells us
that 'hello' is not defined. This means that the Python interpreter looked for a
variable named hello , but it didn't find one.
In [ ]:
hello
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-13-f572d396fae9> in <module>
----> 1 hello
NameError: name 'hello' is not defined
Variables give us a way to store data types. We define a variable using the
variable_name = value syntax:
In [ ]:
x = 5
y = 7
x + y
12
Out[ ]:
The variable name cannot contain spaces; we usually use _ instead. The best variable
names are descriptive ones:
In [ ]:
book_title = 'Hands-On Data Analysis with Pandas'
Variables can be any data type. We can check which one it is with type() , which is a
function (more on that later):
In [ ]:
type(x)
int
Out[ ]:
In [ ]:
type(book_title)
str
Out[ ]:
If we need to see the value of a variable, we can print it using the print() function:
In [ ]:
print(book_title)
Hands-On Data Analysis with Pandas
about:srcdoc Page 3 of 17
python_101 12/09/23, 10:19 AM
Collections of Items
Lists
We can store a collection of items in a list:
In [ ]:
['hello', ' ', 'world']
['hello', ' ', 'world']
Out[ ]:
The list can be stored in a variable. Note that the items in the list can be of different
types:
In [ ]:
my_list = ['hello', 3.8, True, 'Python']
type(my_list)
list
Out[ ]:
We can see how many elements are in the list with len() :
In [ ]:
len(my_list)
4
Out[ ]:
We can also use the in operator to check if a value is in the list:
In [ ]:
'world' in my_list
False
Out[ ]:
We can select items in the list just as we did with strings, by providing the index to select:
In [ ]:
my_list[1]
3.8
Out[ ]:
Python also allows us to use negative values, so we can easily select the last one:
In [ ]:
my_list[-1]
'Python'
Out[ ]:
Another powerful feature of lists (and strings) is slicing. We can grab the middle 2
elements in the list:
about:srcdoc Page 4 of 17
python_101 12/09/23, 10:19 AM
In [ ]:
my_list[1:3]
[3.8, True]
Out[ ]:
... or every other one:
In [ ]:
my_list[::2]
['hello', True]
Out[ ]:
We can even select the list in reverse:
In [ ]:
my_list[::-1]
['Python', True, 3.8, 'hello']
Out[ ]:
Note: This syntax is [start:stop:step] where the selection is inclusive of the start
index, but exclusive of the stop index. If start isn't provided, 0 is used. If stop isn't
provided, the number of elements is used (4, in our case); this works because the stop
is exclusive. If step isn't provided, it is 1.
We can use the join() method on a string object to concatenate all the items of a list
into single string. The string we call the join() method on will be used as the
separator, here we separate with a pipe (|):
In [ ]:
'|'.join(['x', 'y', 'z'])
'x|y|z'
Out[ ]:
Tuples
Tuples are similar to lists; however, they can't be modified after creation i.e. they are
immutable. Instead of square brackets, we use parenthesis to create tuples:
In [ ]:
my_tuple = ('a', 5)
type(my_tuple)
tuple
Out[ ]:
In [ ]:
my_tuple[0]
'a'
Out[ ]:
Immutable objects can't be modified:
about:srcdoc Page 5 of 17
python_101 12/09/23, 10:19 AM
In [ ]:
my_tuple[0] = 'b'
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-31-f792d047bcee> in <module>
----> 1 my_tuple[0] = 'b'
TypeError: 'tuple' object does not support item assignment
Dictionaries
We can store mappings of key-value pairs using dictionaries:
In [ ]:
shopping_list = {
'veggies': ['spinach', 'kale', 'beets'],
'fruits': 'bananas',
'meat': 0
}
type(shopping_list)
dict
Out[ ]:
To access the values associated with a specific key, we use the square bracket notation
again:
In [ ]:
shopping_list['veggies']
['spinach', 'kale', 'beets']
Out[ ]:
We can extract all of the keys with keys() :
In [ ]:
shopping_list.keys()
dict_keys(['veggies', 'fruits', 'meat'])
Out[ ]:
We can extract all of the values with values() :
In [ ]:
shopping_list.values()
dict_values([['spinach', 'kale', 'beets'], 'bananas', 0])
Out[ ]:
Finally, we can call items() to get back pairs of (key, value) pairs:
In [ ]:
shopping_list.items()
dict_items([('veggies', ['spinach', 'kale', 'beets']), ('fruits', 'bananas'
Out[ ]:
), ('meat', 0)])
about:srcdoc Page 6 of 17
python_101 12/09/23, 10:19 AM
Sets
A set is a collection of unique items; a common use is to remove duplicates from a list.
These are written with curly braces also, but notice there is no key-value mapping:
In [ ]:
my_set = {1, 1, 2, 'a'}
type(my_set)
set
Out[ ]:
How many items are in this set?
In [ ]:
len(my_set)
3
Out[ ]:
We put in 4 items but the set only has 3 because duplicates are removed:
In [ ]:
my_set
{1, 2, 'a'}
Out[ ]:
We can check if a value is in the set:
In [ ]:
2 in my_set
True
Out[ ]:
Functions
We can define functions to package up our code for reuse. We have already seen some
functions: len() , type() , and print() . They are all functions that take
arguments. Note that functions don't need to accept arguments, in which case they are
called without passing in anything (e.g. print() versus print(my_string) ).
Aside: we can also create lists, sets, dictionaries, and tuples with functions: list() ,
set() , dict() , and tuple()
Defining functions
We use the def keyword to define functions. Let's create a function called add() with
2 parameters, x and y , which will be the names the code in the function will use to
refer to the arguments we pass in when calling it:
about:srcdoc Page 7 of 17
python_101 12/09/23, 10:19 AM
In [ ]:
def add(x, y):
"""This is a docstring. It is used to explain how the code works and is opti
# this is a comment; it allows us to annotate the code
print('Performing addition')
return x + y
Once we run the code above, our function is ready to use:
In [ ]:
type(add)
function
Out[ ]:
Let's add some numbers:
In [ ]:
add(1, 2)
Performing addition
3
Out[ ]:
Return values
We can store the result in a variable for later:
In [ ]:
result = add(1, 2)
Performing addition
Notice the print statement wasn't captured in result . This variable will only have what
the function returns. This is what the return line in the function definition did:
In [ ]:
result
3
Out[ ]:
Note that functions don't have to return anything. Consider print() :
In [ ]:
print_result = print('hello world')
hello world
If we take a look at what we got back, we see it is a NoneType object:
In [ ]:
type(print_result)
NoneType
Out[ ]:
In Python, the value None represents null values. We can check if our variable is None :
about:srcdoc Page 8 of 17
python_101 12/09/23, 10:19 AM
In [ ]:
print_result is None
True
Out[ ]:
Warning: make sure to use comparison operators (e.g. >, >=, <, <=, ==, !=) to compare to
values other than None .
Function arguments
Note that function arguments can be anything, even other functions. We will see several
examples of this in the text.
The function we defined requires arguments. If we don't provide them all, it will cause an
error:
In [ ]:
add(1)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-49-2558a051bacf> in <module>
----> 1 add(1)
TypeError: add() missing 1 required positional argument: 'y'
We can use help() to check what arguments the function needs (notice the docstring
ends up here):
In [ ]:
help(add)
Help on function add in module __main__:
add(x, y)
This is a docstring. It is used to explain how the code works and is op
tional (but encouraged).
We will also get errors if we pass in data types that add() can't work with:
In [ ]:
add(set(), set())
about:srcdoc Page 9 of 17
python_101 12/09/23, 10:19 AM
Performing addition
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-51-9c946942295c> in <module>
----> 1 add(set(), set())
<ipython-input-41-e34d07952248> in add(x, y)
3 # this is a comment; it allows us to annotate the code
4 print('Performing addition')
----> 5 return x + y
TypeError: unsupported operand type(s) for +: 'set' and 'set'
We will discuss error handling in the text.
Control Flow Statements
Sometimes we want to vary the path the code takes based on some criteria. For this we
have if , elif , and else . We can use if on its own:
In [ ]:
def make_positive(x):
"""Returns a positive x"""
if x < 0:
x *= -1
return x
Calling this function with negative input causes the code under the if statement to run:
In [ ]:
make_positive(-1)
1
Out[ ]:
Calling this function with positive input skips the code under the if statement, keeping
the number positive:
In [ ]:
make_positive(2)
2
Out[ ]:
Sometimes we need an else statement as well:
In [ ]:
def add_or_subtract(operation, x, y):
if operation == 'add':
return x + y
else:
return x - y
This triggers the code under the if statement:
about:srcdoc Page 10 of 17
python_101 12/09/23, 10:19 AM
In [ ]:
add_or_subtract('add', 1, 2)
3
Out[ ]:
Since the Boolean check in the if statement was False , this triggers the code under
the else statement:
In [ ]:
add_or_subtract('subtract', 1, 2)
-1
Out[ ]:
For more complicated logic, we can also use elif . We can have any number of elif
statements. Optionally, we can include else .
In [ ]:
def calculate(operation, x, y):
if operation == 'add':
return x + y
elif operation == 'subtract':
return x - y
elif operation == 'multiply':
return x * y
elif operation == 'division':
return x / y
else:
print("This case hasn't been handled")
The code keeps checking the conditions in the if statements from top to bottom until it
finds multiply :
In [ ]:
calculate('multiply', 3, 4)
12
Out[ ]:
The code keeps checking the conditions in the if statements from top to bottom until it
hits the else statement:
In [ ]:
calculate('power', 3, 4)
This case hasn't been handled
Loops
while loops
With while loops, we can keep running code until some stopping condition is met:
about:srcdoc Page 11 of 17
python_101 12/09/23, 10:19 AM
In [ ]:
done = False
value = 2
while not done:
print('Still going...', value)
value *= 2
if value > 10:
done = True
Still going... 2
Still going... 4
Still going... 8
Note this can also be written as, by moving the condition to the while statement:
In [ ]:
value = 2
while value < 10:
print('Still going...', value)
value *= 2
Still going... 2
Still going... 4
Still going... 8
for loops
With for loops, we can run our code for each element in a collection:
In [ ]:
for i in range(5):
print(i)
0
1
2
3
4
We can use for loops with lists, tuples, sets, and dictionaries as well:
In [ ]:
for element in my_list:
print(element)
hello
3.8
True
Python
In [ ]:
for key, value in shopping_list.items():
print('For', key, 'we need to buy', value)
For veggies we need to buy ['spinach', 'kale', 'beets']
For fruits we need to buy bananas
For meat we need to buy 0
about:srcdoc Page 12 of 17
python_101 12/09/23, 10:19 AM
With for loops, we don't have to worry about checking if we have reached the stopping
condition. Conversely, while loops can cause infinite loops if we don't remember to
update variables.
Imports
We have been working with the portion of Python that is available without importing
additional functionality. The Python standard library that comes with the install of Python
is broken up into several modules, but we often only need a few. We can import whatever
we need: a module in the standard library, a 3rd-party library, or code that we wrote. This
is done with an import statement:
In [ ]:
import math
print([Link])
3.141592653589793
If we only need a small piece from that module, we can do the following instead:
In [ ]:
from math import pi
print(pi)
3.141592653589793
about:srcdoc Page 13 of 17
python_101 12/09/23, 10:19 AM
Warning: anything you import is added to the namespace, so if you create a new
variable/function/etc. with the same name it will overwrite the previous value. For this
reason, we have to be careful with variable names e.g. if you name something sum , you
won't be able to add using the sum() built-in function anymore. Using notebooks or an
IDE will help you avoid these issues with syntax highlighting.
Installing 3rd-party Packages
NOTE: We will cover the environment setup in the text; this is for reference.
We can use pip or conda to install packages, depending on how we created our
virtual environment. The text walks through the commands to create virtual environments
with venv and conda . The environment MUST be activated before installing the
packages for this text; otherwise, it's possible they interfere with other projects on your
machine or vice versa.
To install a package, we can use pip3 install <package_name> . Optionally, we can
provide a specific version to install pip3 install pandas==0.23.4 . Without that
specification, we will get the most stable version. When we have many packages to install
(as we do for this book), we will typically use a [Link] file: pip3
install -r [Link] .
Note: running pip3 freeze > [Link] will send the list of packages
installed in the activate environment and their respective versions to the
[Link] file.
Classes
NOTE: We will discuss this further in the text in chapter 7. For now, it is important to be
aware of the syntax in this section.
So far we have used Python as a functional programming language, but we also have the
option to use it for object-oriented programming. You can think of a class as a way
to group similar functionality together. Let's create a calculator class which can handle
mathematical operations for us. For this, we use the class keyword and define
methods for taking actions on the calculator. These methods are functions that take
self as the first argument. When calling them, we don't pass in anything for that
argument (example after this):
about:srcdoc Page 14 of 17
python_101 12/09/23, 10:19 AM
In [ ]:
class Calculator:
"""This is the class docstring."""
def __init__(self):
"""This is a method and it is called when we create an object of type `C
[Link] = False
def turn_on(self):
"""This method turns on the calculator."""
[Link] = True
def add(self, x, y):
"""Perform addition if calculator is on"""
if [Link]:
return x + y
else:
print('the calculator is not on')
In order to use the calculator, we need to instantiate an instance or object of type
Calculator . Since the __init__() method has no parameters other than self ,
we don't need to provide anything:
In [ ]:
my_calculator = Calculator()
Let's try to add some numbers:
In [ ]:
my_calculator.add(1, 2)
the calculator is not on
Oops!! The calculator is not on. Let's turn it on:
In [ ]:
my_calculator.turn_on()
Let's try again:
In [ ]:
my_calculator.add(1, 2)
3
Out[ ]:
We can access attributes on object with dot notation. In this example, the only attribute
is on , and it is set in the __init__() method:
In [ ]:
my_calculator.on
True
Out[ ]:
Note that we can also update attributes:
about:srcdoc Page 15 of 17
python_101 12/09/23, 10:19 AM
In [ ]:
my_calculator.on = False
my_calculator.add(1, 2)
the calculator is not on
Finally, we can use help() to get more information on the object:
In [ ]:
help(my_calculator)
Help on Calculator in module __main__ object:
class Calculator([Link])
| This is the class docstring.
|
| Methods defined here:
|
| __init__(self)
| This is a method and it is called when we create an object of type
`Calculator`.
|
| add(self, x, y)
| Perform addition if calculator is on
|
| turn_on(self)
| This method turns on the calculator.
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)
... and also for a method:
In [ ]:
help(my_calculator.add)
Help on method add in module __main__:
add(x, y) method of __main__.Calculator instance
Perform addition if calculator is on
about:srcdoc Page 16 of 17
python_101 12/09/23, 10:19 AM
Next Steps
This was a crash course in Python. By no means are you expected to be an expert in the
language to start working through the text. Take some time to play around with this
notebook before trying this chapter's exercises.
← Introduction to Data Analysis </div> Check your Setup Chapter 1 Exercises →
about:srcdoc Page 17 of 17