Python Foundations#

Hello World!#

You can print text with only one command

print('Hola mundo!')
Hola mundo!

Note when a you type text between single (’) or double (”) quotes, the variable becomes a str (string).

name = 'John Titor'
print(name)
John Titor

You can explore the type of each variable with the command type

type(name)
str

Variables as strings allows you to parametrize messages, loggings, titles, etc.

f-strings are useful for combining text and variables

print(f'Hello {name}!')
Hello John Titor!
year = 2023
print(f'{year} is going to be MY year!')
2023 is going to be MY year!

Strings have their own methods, for example you can capitalize every letter

name.upper()
'JOHN TITOR'

Tip

Since Jupyter Lab/Notebook uses an interactive Python kernel it is possible to autocomplete methods and attributes using the TAB key, as long as the object is already defined.

Tip

To explore methods and attributes of an instance, just use dir(variable).

# dir(name)  # Uncomment this line and explore the methods and attributes of a string object.

Math operations#

Python can work as a calculator for basic operations

1 + 2  # Addition
3
100 - 99  # Substraction
1
3 * 4  # Multiplication
12
42 / 4  # Division
10.5
42 // 4  # Floor division
10
42 % 4  ## Modulus
2

Data Structures#

Lists, tuples, sets and dictionaries are data structures in Python that have slightly differences.

Let’s start with the lists that are probably the most natural one.

my_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(my_list[0])
1
type(my_list)
list

You can access to elements of any list using [].

print(my_list[0])
print(my_list[-1])
print(my_list[0:2])
print(my_list[2:])
print(my_list[::2])
print(my_list[:-2])
1
10
[1, 2]
[3, 4, 5, 6, 7, 8, 9, 10]
[1, 3, 5, 7, 9]
[1, 2, 3, 4, 5, 6, 7, 8]

Tuples are similar to lists but you construct them with parenthesis.

my_tuple = (1, 2, 3, 4, 5)
print(my_tuple[4])
5
type(my_tuple)
tuple

Lists can be modifies

my_list.append(100)  
my_list
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100]
my_list[1] = 42
my_list
[1, 42, 3, 4, 5, 6, 7, 8, 9, 10, 100]

However, tuples can’t be modified

my_tuple[1] = 42
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[21], line 1
----> 1 my_tuple[1] = 42

TypeError: 'tuple' object does not support item assignment

Tuples are immutable

try:
    my_tuple.append(50)
except Exception as e:
    print(e)
'tuple' object has no attribute 'append'

Sets are collections unordered, unchangeable (except when you removed or add items), and unindexed.

# Conjuntos
my_set = {2, 1, 1, 1, 2, 2, 3}
print(my_set)
{1, 2, 3}
my_set[0]  # Unordered
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[24], line 1
----> 1 my_set[0]  # Unordered

TypeError: 'set' object is not subscriptable
my_set.remove(1)
my_set
{2, 3}

Finally, dictionaries are sets in which to access their values a key is needed (they are indexed).

my_dict = {
    'Bob': 23,
    'Patrick': 22
}
name = 'Bob'
age = my_dict[name]
print(f'{name} is {age} years old')
Bob is 23 years old
my_dict.values()
dict_values([23, 22])
my_dict.keys()
dict_keys(['Bob', 'Patrick'])

Dictionaries are unordored!

my_dict[0]
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
Cell In[29], line 1
----> 1 my_dict[0]

KeyError: 0

Control Flow#

It is common that while you are coding you want to control certain actions. For these type of taks Python has built-int functionalities, if, elif and else.

x = 7  # Change this value!
lower = 5
upper = 10
if x < lower:
    print(f'{x} is less than {lower}')
elif x < upper:
    print(f'{x} is greater than or equal to {lower} and less than {upper}')
else:
    print(f'{x} is greather than {upper}')
7 is greater than or equal to 5 and less than 10

On the other hand, loops are useful when you want to execute an action several times until a condition is met.

i = 0
while i < 10:
    print(f"{i} square is equal to {i ** 2}")
    i += 1
0 square is equal to 0
1 square is equal to 1
2 square is equal to 4
3 square is equal to 9
4 square is equal to 16
5 square is equal to 25
6 square is equal to 36
7 square is equal to 49
8 square is equal to 64
9 square is equal to 81
for i in range(1, 10, 2):
    if i < 5:
        print(f'{i} is less than 5')
    else:
        print(f'{i} is greather than 5')
1 is less than 5
3 is less than 5
5 is greather than 5
7 is greather than 5
9 is greather than 5

Warning

range objects are not lists!

my_range = range(1, 10, 2)
isinstance(my_range, list)
False
type(my_range)
range
range?
my_range.start
1
my_range.start
1
my_range.stop
10
my_range.step
2

Functions#

To define your own function the syntax is very simple, for example, let’s define the function that returns the integer part of the absolute difference of two numbers.

def abs_diff_floor(x, y):
    """ Returns the integer difference between two values."""
    diff = abs(x - y)
    value = int(diff)
    return value 
abs_diff_floor(20.3, 32.6)
12

Or even encapsulate things we have already done before, such as:

def my_function(x, lower=5, upper=10):
    if x < lower:
        print(f'{x} is less than {lower}')
    elif x < upper:
        print(f'{x} is greater than or equal to {lower} and less than {upper}')
    else:
        print(f'{x} is greather than {upper}')
my_function(5)
5 is greater than or equal to 5 and less than 10
my_function(3, 4, 10)
3 is less than 4

Packages#

There are packages of all kinds for all kinds of tasks in Python, however, it would be inefficient to have everythin available by default when starting a kernel, so the user must manually import or even install them.

For example, how to get the square root of 49? Easy, right?

sqrt(49)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[46], line 1
----> 1 sqrt(49)

NameError: name 'sqrt' is not defined

Wait?! Square root is not a default function?!

Nope! However, as you can imagine, there are a package for this. You only have to import the mathematical operations module that is installed by default in Python, you can’t even imagine its name.

import math  # Yep, math...
math?
math.sqrt(49)
7.0

También hay otras fuinciones, por ejemplo floor

math.floor(2.6)
2

You can explore functions from packages using dir.

dir(math)
['__doc__',
 '__file__',
 '__loader__',
 '__name__',
 '__package__',
 '__spec__',
 'acos',
 'acosh',
 'asin',
 'asinh',
 'atan',
 'atan2',
 'atanh',
 'ceil',
 'comb',
 'copysign',
 'cos',
 'cosh',
 'degrees',
 'dist',
 'e',
 'erf',
 'erfc',
 'exp',
 'expm1',
 'fabs',
 'factorial',
 'floor',
 'fmod',
 'frexp',
 'fsum',
 'gamma',
 'gcd',
 'hypot',
 'inf',
 'isclose',
 'isfinite',
 'isinf',
 'isnan',
 'isqrt',
 'ldexp',
 'lgamma',
 'log',
 'log10',
 'log1p',
 'log2',
 'modf',
 'nan',
 'perm',
 'pi',
 'pow',
 'prod',
 'radians',
 'remainder',
 'sin',
 'sinh',
 'sqrt',
 'tan',
 'tanh',
 'tau',
 'trunc']

IPython#

IPython provides a rich architecture for interactive computing with:

  • A powerful interactive shell.

  • A kernel for Jupyter.

  • Support for interactive data visualization and use of GUI toolkits.

  • Flexible, embeddable interpreters to load into your own projects. Easy to use, high performance tools for parallel computing.

We can take advantage of IPython with some of the magic commands, to read the documenation is as easy as execute the following:

%magic
# List of magic commands
%lsmagic
Available line magics:
%alias  %alias_magic  %autoawait  %autocall  %automagic  %autosave  %bookmark  %cat  %cd  %clear  %colors  %conda  %config  %connect_info  %cp  %debug  %dhist  %dirs  %doctest_mode  %ed  %edit  %env  %gui  %hist  %history  %killbgscripts  %ldir  %less  %lf  %lk  %ll  %load  %load_ext  %loadpy  %logoff  %logon  %logstart  %logstate  %logstop  %ls  %lsmagic  %lx  %macro  %magic  %man  %matplotlib  %mkdir  %more  %mv  %notebook  %page  %pastebin  %pdb  %pdef  %pdoc  %pfile  %pinfo  %pinfo2  %pip  %popd  %pprint  %precision  %prun  %psearch  %psource  %pushd  %pwd  %pycat  %pylab  %qtconsole  %quickref  %recall  %rehashx  %reload_ext  %rep  %rerun  %reset  %reset_selective  %rm  %rmdir  %run  %save  %sc  %set_env  %store  %sx  %system  %tb  %time  %timeit  %unalias  %unload_ext  %who  %who_ls  %whos  %xdel  %xmode

Available cell magics:
%%!  %%HTML  %%SVG  %%bash  %%capture  %%debug  %%file  %%html  %%javascript  %%js  %%latex  %%markdown  %%perl  %%prun  %%pypy  %%python  %%python2  %%python3  %%ruby  %%script  %%sh  %%svg  %%sx  %%system  %%time  %%timeit  %%writefile

Automagic is ON, % prefix IS NOT needed for line magics.

There are two types of magic commands, line ( %) and cell (%%).

%timeit comprehension_list = [i ** 2 for i in range(10000)]
2.69 ms ± 2.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%%timeit

no_comprehension_list = []
for i in range(10000):
    no_comprehension_list.append(i ** 2)
3.15 ms ± 1.01 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Danger

Running a timeit is a test, it does not create such variables.

len(comprehension_list)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[56], line 1
----> 1 len(comprehension_list)

NameError: name 'comprehension_list' is not defined