UniFI logo

Massimo Nocentini, PhD.

May 28, 2020: init



Abstract
A (very concise) introduction to some Python language constructs.
In [3]:
__AUTHORS__ = {'am': ("Andrea Marino", 
                      "andrea.marino@unifi.it",),
               'mn': ("Massimo Nocentini", 
                      "massimo.nocentini@unifi.it", 
                      "https://github.com/massimo-nocentini/",)}

__KEYWORDS__ = ['Python', 'Jupyter', 'language', 'keynote',]

The Python language documentation

Start at https://docs.python.org/3/index.html for everything.

For the tutorial have a look at https://docs.python.org/3/tutorial/index.html, nicely written and complete.

In [69]:
def increment(a):
    return a + 1
In [70]:
increment(0)
Out[70]:
1
In [71]:
increment(1)
Out[71]:
2
In [73]:
L = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
L
Out[73]:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [75]:
LL = [increment(a) for a in L]
LL
Out[75]:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
In [76]:
LLL = [increment(a) for a in LL]
LLL
Out[76]:
[2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
In [78]:
r = range(10)
r
Out[78]:
range(0, 10)
In [79]:
list(r)
Out[79]:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [80]:
map(lambda i: i + 1, L)
Out[80]:
<map at 0x7f0590b631c0>
In [81]:
(lambda i: i + 1)(0)
Out[81]:
1
In [82]:
(lambda i: i + 1)(1)
Out[82]:
2
In [83]:
list(map(lambda i: i + 1, L))
Out[83]:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
In [85]:
M = map(lambda i: i + 1, L)
M
Out[85]:
<map at 0x7f0590b630d0>
In [86]:
next(M)
Out[86]:
1
In [87]:
next(M)
Out[87]:
2
In [88]:
next(M)
Out[88]:
3
In [89]:
next(M)
Out[89]:
4
In [90]:
next(M)
Out[90]:
5
In [91]:
next(M)
Out[91]:
6
In [92]:
next(M)
Out[92]:
7
In [93]:
next(M)
Out[93]:
8
In [94]:
next(M)
Out[94]:
9
In [95]:
next(M)
Out[95]:
10
In [96]:
next(M)
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-96-0666361e9047> in <module>
----> 1 next(M)

StopIteration: 
In [97]:
list(range(10))
Out[97]:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [98]:
list(i for i in range(10))
Out[98]:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [101]:
N = (i for i in range(10))
N
Out[101]:
<generator object <genexpr> at 0x7f0568ef1040>
In [102]:
list(N)
Out[102]:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [103]:
next(N)
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-103-0f4723c98d79> in <module>
----> 1 next(N)

StopIteration: 

we want to build an object that denotes a Bernoulli random variable.

it is desired to be able to sample from that variable an arbitrary number of times, not known at design time.

In [107]:
from random import random # import the random generator, to be used to sample from the uniform distribution
In [108]:
random() # a quick check that the random function works
Out[108]:
0.03068991525009368
In [109]:
int(True) # this is a very quick check to see if a Boolean can be used as integer
Out[109]:
1
In [110]:
def Bernoulli(p):
    'This is a generator for a Bernoulli random variable of parameter `p` for success.'
    
    while True:              # forever we loop
        r = random()         # get a sample
        yield int(r <= p)    # if that sample denotes a success or a failure we *yield* that outcome
In [112]:
yield # if we evaluate *yield* not in a context, Python raises an error because it is a construct
  File "<ipython-input-112-f8373fab0a85>", line 1
    yield # if we evaluate *yield* not in a context, Python raises an error because it is a construct
    ^
SyntaxError: 'yield' outside function
In [113]:
help(Bernoulli)
Help on function Bernoulli in module __main__:

Bernoulli(p)
    This is a generator for a Bernoulli random variable of parameter `p` for success.

In [115]:
B = Bernoulli(p=0.6) # B is our random variable
B
Out[115]:
<generator object Bernoulli at 0x7f0568d4cf20>
In [116]:
next(B)
Out[116]:
1
In [117]:
next(B)
Out[117]:
0
In [118]:
next(B)
Out[118]:
1
In [122]:
sample = [next(B) for _ in range(1000)]
sample[:20] # just for a quick evaluation, we print the first 20 elements
Out[122]:
[0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0]
In [123]:
from collections import Counter
In [124]:
Counter(sample)
Out[124]:
Counter({0: 421, 1: 579})
In [126]:
B_flip = map(lambda o: 1-o, B)
B_flip
Out[126]:
<map at 0x7f0568efe040>
In [127]:
sample = [next(B_flip) for _ in range(1000)]
sample[:20] # just for a quick evaluation, we print the first 20 elements
Out[127]:
[0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]
In [128]:
def Bernoulli(p):
    'This is a generator for a Bernoulli random variable of parameter `p` for success.'
    
    while True:              # forever we loop
        r = random()         # get a sample
        o = int(r <= p)      # if that sample denotes a success or a failure we *yield* that outcome
        print('B ' + str(o))
        yield o
In [132]:
def flip(o):
    print('flip')
    return 1-o
In [133]:
B_flip = map(flip, Bernoulli(p=0.9))
B_flip
Out[133]:
<map at 0x7f0568ef89a0>
In [135]:
sample = [next(B_flip) for _ in range(20)]
Counter(sample)
B 0
flip
B 1
flip
B 1
flip
B 1
flip
B 1
flip
B 1
flip
B 1
flip
B 1
flip
B 1
flip
B 1
flip
B 1
flip
B 1
flip
B 1
flip
B 1
flip
B 0
flip
B 1
flip
B 1
flip
B 1
flip
B 1
flip
B 1
flip
Out[135]:
Counter({1: 2, 0: 18})
In [151]:
class A(object):
    
    def __init__(self, j):
        self.j = j
    
    def __add__(self, i):
        return self.j + i
    
    def __radd__(self, i):
        return self.j + i
    
    def __lt__(self, i):
        return self.j < i
In [137]:
def B(b):
    pass
In [138]:
B
Out[138]:
<function __main__.B(b)>
In [140]:
B(3) is None
Out[140]:
True
In [141]:
def B(b):
    ...
In [142]:
increment(4)
Out[142]:
5
In [143]:
a = A()
increment(a)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-143-a46ef281d6c6> in <module>
      1 a = A()
----> 2 increment(a)

<ipython-input-69-d2b3a35173e0> in increment(a)
      1 def increment(a):
----> 2     return a + 1

TypeError: unsupported operand type(s) for +: 'A' and 'int'
In [145]:
a = A()
increment(a)
Out[145]:
2
In [147]:
A(3) + 1
Out[147]:
4
In [148]:
1 + A(3)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-148-087a68ad802d> in <module>
----> 1 1 + A(3)

TypeError: unsupported operand type(s) for +: 'int' and 'A'
In [150]:
1 + A(3)
Out[150]:
4
In [152]:
A(4) < 2
Out[152]:
False