Open In Colab

1. Python Overview#

Python is an interpreted programming language oriented to easy-readable coding, unlike compiled languages like C/C++ and Fortran, where the syntax usually does not favor the readability. This feature makes Python very interesting when we want to focus on something different than the program structure itself, e.g. on Computational Methods, thereby allowing to optimize our time, to debug syntax errors easily, etc.

Official page

Wikipedia

1.1. Python Philosophy#

  1. Beautiful is better than ugly.

  2. Explicit is better than implicit.

  3. Simple is better than complex.

  4. Complex is better than complicated.

  5. Flat is better than nested.

  6. Sparse is better than dense.

  7. Readability counts.

  8. Special cases aren’t special enough to break the rules. (Although practicality beats purity)

  9. Errors should never pass silently. (Unless explicitly silenced)

  10. In the face of ambiguity, refuse the temptation to guess.

  11. There should be one– and preferably only one –obvious way to do it. (Although that way may not be obvious at first unless you’re Dutch)

  12. Now is better than never. (Although never is often better than right now)

  13. If the implementation is hard to explain, it’s a bad idea.

  14. If the implementation is easy to explain, it may be a good idea.

  15. NameSpaces are one honking great idea – let’s do more of those!


1.2. Biblography#

[1f] Ani Adhikari and John DeNero, Computational and Inferential Thinking


1.3. String, Integer, Float#

The basic types of variables in Python are:

str:

Illustrated with the hello world standard

#Strings
hello='hola'

int

#Integer
n=3

float

x=3.5

1.4. Functions I#

Python includes a battery of predefined functions which takes an input and generates an output. For example, to check the type of variable we can used the predefined function

1.4.1. isinistance:#

isinstance(hello,str)
True

Activity: In the next cell check if n is a float type of variable

1.4.2. print#

See: https://pyformat.info/

To write the Hello world program in python we must first introduce the concept of function. It is the same in mathematics, were something called function receives a number and return back another number. For example, the function to square a number is

(1.1)#\[\begin{equation} f(x)=x^2\,, \end{equation}\]

\(x\) is called the argument of the function \(f\), and the returned value is the evaluation of \(f(x)\).

In Python there are a lot of such a functions. In particular there is a function called print which takes strings (see below) as input and return the same string as output. In this way, the hello world program in Python is one of the most simple between all the programming languages:

1.5. Hello World!#

print('Hello World!')
Hello World!

And also allows scripting: (This code should be copied on a file ‘hello.py’)

#! /usr/bin/python

#This is a comment
print('Hello World!')
Hello World!

The recommended way to print a variable in Python is to use the .format method of the function print by preceding the sring with the letter f. Inside the string any variable between curly brackets, {variable}, can be used

hello='Hello World!'
print(f'{hello}')
Hello World!

Activity: Change the values of the previous string variables to print Hello World! in Spanish

x=23456.5678545
print(f'{x:.2f}')
23456.57

Activity: Print with 3 decimal places

1.6. Functions II#

In Python it is possible also to create new functions. We illustrate the format to define a function in Python with the implementation of the function \(f(x)=x^2\), where to write an exponent: \({}^2\), in Python we must use the format: **2.

1.6.1. Implicit functions#

f=lambda x:x**2
isinstance(f,str)
False
type(f)
function
f(3)
9

1.6.2. Explicit functions#

The standard function build may include the help for the function

def f(x):
    '''
    Calculates the square of `x`
    '''
    return x**2

f(5)

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

f(x)
    Calculates the square of `x`

The full list of built-in functions is in https://docs.python.org/3/library/functions.html and the specific help for a function, for example print can be checked with https://docs.python.org/3/library/functions.html#print

def f(x,y):
    '''
    Multiply two numbers
    '''
    return x*y
f(3,2)
6
#It is possible to assign default arguments
def f(x,y=2):
    '''
    Multiply two numbers. By default the second is 2
    '''    
    return x*y
#When evaluating, we can omit the default argument
f(3)
6
f(2,3)
6
f(2,y=5)
10
#It is possible to specify explicitly the order of the arguments
def f(x,y):
    '''
    evaluates x to the power y
    '''    
    return x**y
print( 'f(1,2)=',f(1,2) )
print( 'f(2,1)=',f(y=1,x=2) )
f(1,2)= 1
f(2,1)= 2

1.6.3. Implicit functions of several arguments#

Implicit functions are usdeful when we want to use a function once.

f = lambda x,y: x**y
f(3,2)
9

1.6.4. Nested functions#

#It is possible to pass functions as arguments of other function
def f2( f, x ):
    return f(x)**2

#We can define a new function explicitly
def f(x):
    return x+2

print(f(2))
print(f2(f,2))


#Or define the function implicitly
print ("Implicit: f(2)^2 =", f2(lambda x:x+2,2) )
4
16
Implicit: f(2)^2 = 16

1.6.5. Inner functions with returned internal function#

def hola(func):
    def function_wrapper(x):
        res = 'hola mundo '+str(func(x))
        return res
    return function_wrapper

def mundo(n):
    return n+' y despiadado'
foo=hola(mundo)
foo('cruel')
'hola mundo cruel y despiadado'

or just

hola(mundo)('cruel')
'hola mundo cruel y despiadado'

1.6.6. Decorators#

From: [@] https://realpython.com/primer-on-python-decorators/

By definition, a decorator is a function that takes another function and extends the behavior of the latter function without explicitly modifying it.

See also: https://www.python-course.eu/python3_decorators.php.

The previos function hola can be used as a decorator, in a such way that it is not necesary to call it directly but only to call its argument

@hola
def mundano(n):
    return n+' y despiadado'

@hola
def mundito(n):
    return n+' y floreciente'

Instead of hola(mundano)('cruel') we can just use directly the new decorated function:

mundano('cruel')
'hola mundo cruel y despiadado'
mundito('brillante')
'hola mundo brillante y floreciente'

[@]:

Put simply: decorators wrap a function, modifying its behavior.

1.7. Arithmetics#

1.7.1. Sum#

5.89+4.89
10.78

Activity: Sum strings: Hint: use +' '+

Activity: Sum integers

Example

print(hello+' '+world+'!')
Hola Mundo!

1.7.2. Multiplication#

120*4.5
540.0

Example String multiplied by integer:

print('='*80)
================================================================================

1.7.3. Division#

#Python 3 does support complete division
100/3
33.333333333333336
100/3.
33.333333333333336

Force integer division

100//3
33

1.7.4. Module#

10%2
0
20%3
2

1.7.5. Power#

2**6
64

1.7.6. Scientific notation#

\(1\times 10^3=10^3=1000\)

1E3
1000.0

\(2\times 10^3=2000\)

2E3
2000.0
\[\frac{ \dfrac{10^{24}}{3}+2.9\times 10^{23}}{10^2}\]
(1.0e24/3. + 2.9e23)/1e-2
6.233333333333333e+25
sin=0.3
isinstance(sin,float)
True
from math import *

Keep the name space

Use name.last_name

isinstance(sin,float)
False
sin
<function math.sin(x, /)>
import math as m
import cmath as cm
import numpy as np
#Recommended option:
import numpy.lib.scimath as sc
isinstance(sin,float)
True
m.sin(0.5)
0.479425538604203
cm.sin(0.5)
(0.479425538604203+0j)
np.sin(0.5)
0.479425538604203
sp.sin(0.5)
/home/restrepo/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:1: DeprecationWarning: scipy.sin is deprecated and will be removed in SciPy 2.0.0, use numpy.sin instead
  """Entry point for launching an IPython kernel.
0.479425538604203

1.7.7. Complex numbers#

1j**2
(-1+0j)
z=2+3.2j
isinstance(z,complex)
True

Attributes and methods:

z.real,z.imag,z.conjugate()
(2.0, 3.2, (2-3.2j))
z+3*z
(8+12.8j)
z*z
(-6.240000000000002+12.8j)
z*z.conjugate()
(14.240000000000002+0j)

math does not work with complex numbers

m.asin(2+0j)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-162-1385535d58fd> in <module>
----> 1 m.asin(2+0j)

TypeError: can't convert complex to float
cm.asin(2)
(1.5707963267948966+1.3169578969248166j)

numpy requires proper input

np.arcsin(2)
/usr/local/lib/python3.7/dist-packages/ipykernel_launcher.py:1: RuntimeWarning: invalid value encountered in arcsin
  """Entry point for launching an IPython kernel.
nan
np.arcsin(2+0j)
(1.5707963267948966+1.3169578969248166j)

numpy.lib.scimath imported as sc here, is from sc?:

Wrapper functions to more user-friendly calling of certain math functions whose output data-type is different than the input data-type in certain domains of the input. Function with some parts of its domain in the complex plane like, sqrt, log, log2, logn, log10, power, arccos, arcsin, and arctanh.

np.lib.scimath.arcsin(2)
(1.5707963267948966+1.3169578969248166j)
sc.arcsin(2)
(1.5707963267948966+1.3169578969248166j)
import ipywidgets as widgets
@widgets.interact
def f(x=(0,2)):
    print(np.abs(sc.arcsin(x)))
sc.arcsin([2,3])
array([1.57079633+1.3169579j , 1.57079633+1.76274717j])

1.8. Lists, Tuples, Dictionaries and Sets#

1.8.1. Lists#

Lists are useful when you want to store and manipulate a set of elements (even of different types).

#A list is declared using [] and may content different type of objects
lista = ["abc", 42, 3.1415]
lista
['abc', 42, 3.1415]
#First element of the list
lista[0]
'abc'
#Last element of the list
lista[-1]
3.1415
#Adding a new element (boolean element)
lista.append(True)
lista
['abc', 42, 3.1415, True]

WARNING:

newlista=lista
newlista.append('algo')
newlista
['abc', 42, 3.1415, True, 'algo']
lista
['abc', 42, 3.1415, True, 'algo']
newlista=lista.copy()
newlista.append(5)
print(newlista)
['abc', 42, 3.1415, True, 'algo', 5]
lista.copy?
Signature: lista.copy()
Docstring: Return a shallow copy of the list.
Type:      builtin_function_or_method
import copy
copy.copy(lista)
['abc', 42, 3.1415, True, 'algo']
copy.deepcopy(lista)
['abc', 42, 3.1415, True, 'algo']
lista
['abc', 42, 3.1415, True, 'algo']
#Inserting a new second element 
lista.insert(1, "I am second")
lista
['abc', 'I am second', 42, 3.1415, True, 'algo']
#Deleting the third element of the list
del lista[3]
lista
['abc', 'I am second', 42, True, 'algo']
#Reassign the first element of the list
lista[0] = "xyz"
lista
['xyz', 'I am second', 42, True, 'algo']

1.8.1.1. Slicing:#

Extract elements from a list, l from one given index to another given index. We pass slice instead of index like this:

l[start:end]

We can also define the step, like this:

l[start:end:step]

If start is not passed it is considered 0. If end is not passed it is considered length of array in that dimension. The end can given in reverse order by assigning a minus signus to the index. For example -1 means the last element, while -2 means the penultimate, and so on and so forth.

#Showing the elements from 0 to 2
lista[0:3]
['xyz', 'I am second', 42]
lista[:3]
['xyz', 'I am second', 42]
#Showing the last two elements
lista[-2:]
[True, 'algo']
#Showing elements two by two
lista[::2]
['xyz', 42, 'algo']
#Reverse order
newlista=lista[::-1]
newlista
['algo', True, 42, 'I am second', 'xyz']
lista
['xyz', 'I am second', 42, True, 'algo']
#also as
lista.reverse()
lista
['algo', True, 42, 'I am second', 'xyz']
list(reversed(lista))
['algo', True, 42, 'I am second', 'xyz']
lista
['xyz', 'I am second', 42, True, 'algo']

1.8.1.2. Embedded lists#

#It is possible to embed a list within another
embedded_list = [lista, [True, 42]]
embedded_list
[['xyz', 'I am second', 42, True, 'algo'], [True, 42]]
#Second element of the first list
embedded_list[0][1]
'I am second'
#A matrix as a list of embedded lists
A = [ [1,2], [3,4] ]
A
[[1, 2], [3, 4]]

Activity: Obtain entry \(A_{01}\) of the previous matrix, where $\( A=\begin{pmatrix} A_{00} & A_{01}\\ A_{10} & A_{11}\\ \end{pmatrix} \)$

A[0][1]
2

1.8.1.3. Sum of lists#

#When two list are added, the result is a new concatenated list
[1,2,"ab",True,[1,2]] + [3.1415,"Pi","circle"]
[1, 2, 'ab', True, [1, 2], 3.1415, 'Pi', 'circle']

Activity Add a third row with integer values to the previous \(A\) matrix

A.insert(1,[7,8])
A
[[1, 2], [7, 8], [3, 4], [7, 8]]

An additional ingredient is the append method of a Python list. It update the elements of the list without update explicitly the variable with some equal reasignment.

y=[]
y.append(2)
print(f'after append 2 to [] : {y}')
y.append(5)
print(f'after append 5 to [2]: {y}')
after append 2 to [] : [2]
after append 5 to [2]: [2, 5]

functions to generate lists:

  • range

list(range(3))
[0, 1, 2]

Conditional in lists:

  • in

  • any

  • all

3 in [4,5,6]
False
[7,8] in [4,5,6,[7,8]] 
True
any([False,False,False])
False
any([False,False,True])
True
all([False,False,True])
False
all([True,True,True])
True

1.8.1.4. List Comprehension#

Taken from here: List comprehensions provide a concise way to create lists. Common applications are to make new lists where each element is the result of some operations applied to each member of another sequence or iterable, or to create a subsequence of those elements that satisfy a certain condition.

[x for x in range(2,10,2)]
[2, 4, 6, 8]
[x**2 for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
[x**2 for x in range(2,10,2)]
[4, 16, 36, 64]
[[x, y] for x in [1,2,3] for y in [3,1,4] if x != y]
[[1, 3], [1, 4], [2, 3], [2, 1], [2, 4], [3, 1], [3, 4]]
[[x, y] for x in [1,2,3] for y in [1,2,3] if x != y]
[[1, 2], [1, 3], [2, 1], [2, 3], [3, 1], [3, 2]]

Activity: Tuplas con pares diferentes sólo

l=[ ['A','B','C'],['D','E','F'],['G','H','I']  ]

¡Filtered lists!:

we can extract the list that contains 'H'

[ll for ll in l if 'H' in ll]
[['G', 'H', 'I']]
'H' in l
False
['G','H','I'] in l
True

1.8.1.5. Reversed comprehension#

We can use the method reversed(...) to generate an iterator with the revesersed list so that the original list is kept.

lista
['xyz', 'I am second', 42, True]
print('reversed: {}'.format( list(reversed(lista)) ))
print('original: {}'.format(lista))
reversed: ['algo', True, 42, 'I am second', 'xyz']
original: ['xyz', 'I am second', 42, True, 'algo']

1.8.2. Tuples#

A tuple is almost equal to a list, except that once declared its elements, it is not possible to modify them. Therefore, tuples are useful only when you want to store some elements but not modify them.

#A tuple is declared using ()
tupla = ("abc", 42, 3.1415)
tupla
('abc', 42, 3.1415)

Note: single element tuple

(2) #equivalent to 2
2
t=(2,)
len(t)
1
t[0]
2

For creating an empty tuple

(,)

or creating the instance of the class tuple

t=tuple()
t
()

The comprenhension tuple also works

tuple( (t for t in tupla)  )
('abc', 42, 3.1415)
#It is not possible to add more elements
tupla.append("xy")
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-87-4cc56b436273> in <module>
      1 #It is not possible to add more elements
----> 2 tupla.append("xy")

AttributeError: 'tuple' object has no attribute 'append'
#It is not possible to delete an element
del tupla[0]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-88-c05ec550c1d0> in <module>
      1 #It is not possible to delete an element
----> 2 del tupla[0]

TypeError: 'tuple' object doesn't support item deletion
#It is not possible to modify an existing element
tupla[0] = "xy"
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-89-4e97d1641827> in <module>
      1 #It is not possible to modify an existing element
----> 2 tupla[0] = "xy"

TypeError: 'tuple' object does not support item assignment

1.8.2.1. Some list functions#

any can extract a true value from a comprension tuple (see also all: https://docs.python.org/3/library/functions.html#all). In fact, for the following nested list:

l=[ ['A','B','C'],['D','E','F'],['G','H','I']   ]

we can extract the list that contains 'H' more easily

[ll for ll in l]
[['A', 'B', 'C'], ['D', 'E', 'F'], ['G', 'H', 'I']]
any((s=='L' for s in ['G', 'H', 'I']))
False
[ll for ll in l if any( s=='H' for s in ll  ) ]
[['G', 'H', 'I']]

With the function zip we can generate dictionary-like tuple from two lists:

list(zip( ['A','B','C'],[1,2,3]  ))
[('A', 1), ('B', 2), ('C', 3)]
list(zip( ['A','B','C'],[1,2,3]  ))
[('A', 1), ('B', 2), ('C', 3)]

1.8.3. Dictionaries#

Dictionaries are labeled lists: with keys and values. They are extremely useful when manipulating complex data. In Wolfram Alpha the equivalent object is called Associations

#A dictionary is declared using {}, and specifying the name of the component, then the character : followed by the element to store.
dictionary={ 'Kenia'         :'Nairobi',
             'Noruega'       :'Oslo',
             'Finlandia'     :'Helsinski',
             'Rusia'         :'Moscú',
             'Rio de Janeiro':'Rio',
             'Japón'         :'Tokio',
             'Colorado'      :'Denver',
             'Alemania'      :'Berlin',
             'Colombia'      :'Bogotá'}
print(dictionary)
#Note the order in a dictionary does not matter as one identifies a single element through a string, not a number
{'Kenia': 'Nairobi', 'Noruega': 'Oslo', 'Finlandia': 'Helsinski', 'Rusia': 'Moscú', 'Rio de Janeiro': 'Rio', 'Japón': 'Tokio', 'Colorado': 'Denver', 'Alemania': 'Berlin', 'Colombia': 'Bogotá'}

Instead of a number, an element of a dictionary is accessed with the key of the component

dictionary
{'Kenia': 'Nairobi',
 'Noruega': 'Oslo',
 'Finlandia': 'Helsinski',
 'Rusia': 'Moscú',
 'Rio de Janeiro': 'Rio',
 'Japón': 'Tokio',
 'Colorado': 'Denver',
 'Alemania': 'Berlin',
 'Colombia': 'Bogotá'}
print('{}{}'.format( dictionary['Japón'], dictionary['Rio de Janeiro']) )
Tokio ♥ Rio
#The elements of the dictionary may be of any type
dictionary2 = { "Enteros":[1,2,3,4,5], 
                "Ciudad" :"Medellin", 
                "Cédula" :1128400433, 
                "Colores":["Amarillo", "Azul", "Rojo"] }
print(dictionary2["Colores"][1])
Azul
#The elements of the dictionary can be modified only by changing directly such an element
dictionary2["Ciudad"] = "Bogota"
print(dictionary2)
{'Enteros': [1, 2, 3, 4, 5], 'Ciudad': 'Bogota', 'Cédula': 1128400433, 'Colores': ['Amarillo', 'Azul', 'Rojo']}
#Adding a new element is possible by only defining the new component
dictionary2["Pais"] = "Colombia"
dictionary2["País"] = "Chile"
print( dictionary2 )
{'Enteros': [1, 2, 3, 4, 5], 'Ciudad': 'Bogota', 'Cédula': 1128400433, 'Colores': ['Amarillo', 'Azul', 'Rojo'], 'Pais': 'Colombia', 'País': 'Chile'}
dictionary2.update({'Continente':'América'})
dictionary2
{'Enteros': [1, 2, 3, 4, 5],
 'Ciudad': 'Bogota',
 'Cédula': 1128400433,
 'Colores': ['Amarillo', 'Azul', 'Rojo'],
 'Pais': 'Colombia',
 'País': 'Chile',
 'Continente': 'América'}

List-like dictionary

l={0:45,1:345,2:987}
l[0]
45
l={0.3:45}
l[0.3]
45
l={0:45,1:345,2:987}
l[3]=2022
l
{0: 45, 1: 345, 2: 987, 3: 2022}
d={True:'Verdadero'}
d[True]
'Verdadero'
#The command del can be also used for deleting an element, as a list
del dictionary2["Pais"]
print(dictionary2)
{'Enteros': [1, 2, 3, 4, 5], 'Ciudad': 'Bogota', 'Cédula': 1128400433, 'Colores': ['Amarillo', 'Azul', 'Rojo'], 'País': 'Chile'}

With the previous zip function to create tuples from lists, we can create a dictionary from the two lists:

list(zip( ['A','B','C'],[1,2,3]  ))
[('A', 1), ('B', 2), ('C', 3)]
dict(zip( ['A','B','C'],[1,2,3]  ))
{'A': 1, 'B': 2, 'C': 3}

Activity: Creates a diccionary for the values: ['xyz',3,4.5] with integer keys starting with zero. In this way, the dictionary could behave as list

1.8.4. JSON object#

A list of dictionaries is simple example of a non-relational database which can be represented as a JSON object. Their main advantage is that with the proper glosary for the keys of the dictionaries the data analysis is well expressed through the impledmented code

1.8.4.1. Two basic concepts#

  • list

l=['cat','dog','cow']
l[1]
'dog'
  • dictionary

d={'animal':'cat','fruit':'mango'}
d['fruit']
'mango'

1.8.4.2. They can be nested!#

farm={'animals':l,'fruits':['mango','banana']}
farm['animals'][1]
'dog'

They can be saved

import json
f=open('farm.json','w')
json.dump(farm,f)
f.close()
%pycat farm.json
{"animals": ["cat", "dog", "cow"], "fruits": ["mango", "banana"]}

They can be read

f=open('farm.json','r')
farm=json.load(f)
f.close()
farm
{'animals': ['cat', 'dog', 'cow'], 'fruits': ['mango', 'banana']}

They can be visualized (in Firefox ) or from any advanced editor

from IPython.display import JSON
JSON(farm)
<IPython.core.display.JSON object>

The can be diagramatically represented: ovals are dictionaries and squares are lists

img

See the [tweet object]

Any information set can be represented as a single JSON scheme (JSON object)

  • Spreadsheet

  • SQL Relational database

  • Tweet

  • Facebook post

  • Jupyter notebook

  • Scientific article

In practice, any information set can be represented as a few as possible JSON objects:

Non-Relational database (MongoDB)

A non-relational database is a database that does not use the tabular schema of rows and columns found in most traditional database systems. Instead, non-relational databases use a storage model that is optimized for the specific requirements of the type of data being stored.

From microsoft

1.8.4.3. Example:#

Extract information from a JSON object

people=[{'name':'Juan',  'last_name':'Valdez','age':25},
        {'name':'Álvaro','last_name':'Uribe', 'age':69}
       ]

Extract the last names from the people data base (Note the very expressive sintaxis!)

[d.get('last_name') for d in people]
['Valdez', 'Uribe']

d.get('last_name') is safer than d['last_name']

Sum the ages

sum([d.get('age') for d in people])
94

1.8.5. Sets#

Z2={0,1}
Z3={0,1,2}
Z2.intersection(Z3)
{0, 1}
Z2.union(Z3)
{0, 1, 2}
Z2.issubset(Z3)
True

The elements of the set must be unique and sorted

U={1,2,2,2,4,4,-2}
U
{-2, 1, 2, 4}

Aplicación: Obtenga los elementos únicos de una lista

l=[3,7,1,9,4,6,6]
list(set(l))
[1, 3, 4, 6, 7, 9]

1.9. Conditionals#

1.9.1. if#

Conditionals are useful when we want to check some condition. The statements elif and else can be used when more than one condition need to be used, or when there is something to do when some condition is not fulfilled.

x = 10
y = 2
if x > 5 and y==2:
    print( "True" )
True
x = 4
y = 3
if x>5 or y<2:
    print( "True 1" )
elif x==4:
    print( "True 2" )
else:
    print( "False" )
True 2

1.10. Loops#

1.10.1. for#

For cycles are specially useful when we want to sweep a set of elements with a known size.

for i in range(0,5,1):
    print( i, i**2)
0 0
1 1
2 4
3 9
4 16

Activity: change print with format

suma = 0
for i in range(10):
    suma += i**2 # suma = suma + i**2
print ( f"The result is {suma}" )
The result is 285
for language in ['Python', 'C', 'C++', 'Ruby', 'Java']:
    print ( language )
Python
C
C++
Ruby
Java

As we see before, for can be used to build comprenhension lists

serie = [ i**2 for i in range(1,10) ]
print( serie )
[1, 4, 9, 16, 25, 36, 49, 64, 81]

1.10.2. while#

While cycles are specially useful when we want to sweep a set of elements with an unknown size.

Before we check the functions input and int of Python

edad=input('¿What is your age, Jesus?:\n')
int(edad)
33

Bonus: some time the input must be hidden

import getpass
c=getpass.getpass('Contraseña')
c
'secreto'

Now the while examples

#! /usr/bin/python
number = int(input("Write a negative number: "))
while number > 0:
    print("You wrote a positive number. Do it again")
    number = int(input("Write a negative number: "))
print("Thank you!")
You wrote a positive number. Do it again
You wrote a positive number. Do it again
Thank you!
import random
x = 0
while x<0.9:
    x = random.random()
    print( x )
print ("The selected number was", x )
0.2752802751365522
0.454951670912941
0.5693802843954813
0.40177621529970386
0.5723817621908507
0.07290420456928348
0.8490188174025372
0.7299725403288975
0.643209656068515
0.489899543622623
0.2264889834942161
0.20635090393901312
0.09683376918376296
0.14509871628728777
0.016240658000300057
0.7959386412781978
0.4201817808266113
0.461661957674957
0.8050501425691475
0.35466072752783484
0.46678267891050707
0.21167232860716456
0.4891465944627792
0.36677308439573475
0.7677369600825966
0.16631714193575065
0.0017489053343822114
0.819215365205134
0.9499334082744344
The selected number was 0.9499334082744344

1.11. Methods and attributes of objects in Python#

All the objects in Python, including the function and variable types discussed here, are enhanced with special functions called methods, which are implemented after a point of the name of the variable, in the format:

variable.method()

Some times, the method can even accept some arguments.

The objects have also attributes which describe some property of the object. They do not end up with parenthesis:

variable.attribute

1.11.1. Methods#

For example. The method .keys() of a variable dictionary allows to obtain the list of keys of the dictionary. For example

dictionary.keys()
dict_keys(['Kenia', 'Noruega', 'Finlandia', 'Rusia', 'Rio de Janeiro', 'Japón', 'Colorado', 'Alemania', 'Colombia'])

And the list of values:

dictionary.values()
dict_values(['Nairobi', 'Oslo', 'Helsinski', 'Moscú', 'Rio', 'Tokio', 'Denver', 'Berlin', 'Bogotá'])

For strings we have for example the conversion to lower case

s="Juan Valdez"
s.lower()
'juan valdez'
"juan valdez".title()
'Juan Valdez'
"juan valdez".upper()
'JUAN VALDEZ'

1.11.2. Attributes#

a=1j
a.imag
1.0
a.real
0.0
z=3+5j

with attributes

z.real
3.0
z.imag
5.0

and the method:

z.conjugate()
(3-5j)

In the notebook, All the methods and attributes of an object can be accessed by using the <TAB> key after write down the point:

variable.<TAB>
z.

Activity: Check the methods and attributes of the dictionary dictonary. HINT: Check the help for some of them by using a question mark, “?”, at the end:

variable.method?

1.12. Unicode#

Is an standard to encode characters. In Python 3, around 120.000 characters can be used to define variables. For example, one right to left arabic variable can be defined as

=2
print('Arabic character values is: {}'.format())
Arabic character values is: 2

Spanish example

mamá='Lola'

In Jupyter lab greek symbols can be accessed by using its LaTeX command follow by the <TAB> key.

\alpha+<TAB>=0.5 could convert on the fly to

α=0.5
print(α)
0.5

Alternatively yuo can copy the character from some list of unicode symbols, like this one.

Activity: Define a Greek variable by using a symbol from the previous list

1.13. Stop exection#

Stop the program if a condition is not satisfied

See: https://realpython.com/python-exceptions/

x = 6
if x > 5:
    raise Exception('x should not exceed 5. The value of x was: {}'.format(x))

print(f'codo continues here: {x}<=5')
---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
/tmp/ipykernel_30232/2136376697.py in <module>
      1 x = 6
      2 if x > 5:
----> 3     raise Exception('x should not exceed 5. The value of x was: {}'.format(x))
      4 
      5 print(f'codo continues here: {x}<=5')

Exception: x should not exceed 5. The value of x was: 6

1.14. Final remarks#

Make your google Python questions in English and check specially the https://stackoverflow.com/ results.

Activity: Make some Python query in Google and paste the example code below

input('What was the Google query that you ask?:\n')
β

Sample code:

1.15. Parallel#

foo(x) → delayed(foo)(x)
>>> from joblib import Parallel, delayed
>>> from math import sqrt
>>> Parallel(n_jobs=8)(delayed(sqrt)(i**2) for i in range(10))
[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]

See also: https://docs.python.org/3/library/multiprocessing.html

1.16. Scientific libraries#

1.17. Pandas#

1.18. Matplotlib#

1.19. Jupyter notebooks#

1.20. Appendix#

Summary with ChatGPT