Category Archives: Python

Programmazione funzionale – si può fare con Python?

bbOK, forse non è l’attrezzo migliore ma vorrei affrontare l’argomento un po’ alla larga. E questo è solo l’inizio. Probabilmente continuerò per questo argomento — forse, chissà :wink: :mrgreen:

Per un caso di pura serendipity trovo questa definizione:

Functional programming (FP) is based on a simple premise with far-reaching implications: we construct our programs using only pure functions—in other words, functions that have no side effects. What are side effects? A function has a side effect if it does something other than simply return a result, for example:

  • Modifying a variable;
  • Modifying a data structure in place;
  • Setting a field on an object;
  • Throwing an exception or halting with an error;
  • Printing to the console or reading user input;
  • Reading from or writing to a file;
  • Drawing on the screen.

È l’inizio di Functional Programming in Scala di Paul Chiusano e Rúnar Bjarnason — grazie a Luis Souto Graña che me l’ha segnalato :grin:
Ecco messo in questi termini non è che si può andare molto lontano. Ma se invece ammettiamo che non tutte le funzioni siano pure forse qualcosa si può fare.

Una richiesta in proposito su Stack Overflow è stata chiusa da tutto un gruppo di amministratori: We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion.

Questa query functional programming in python dimostra un caso pratico. Ma Python per queste cose si dimostra particolarmente inefficiente.

f0E poi un pythonista userebbe probabilmente la list comprehension:

f1Seguono poi un paio (abbondante) di discussioni chiuse per vari motivi. E anche questa richiesta How to construct such a functional-programming tool in Python? molto specifica, imho, ha un paio di risposte pythoniche non semplicissime, anzi :evil:

La mia preferita è questa: Why program functionally in Python?
Anche perché Paul, fa ha la mia questione:  I understand that functional languages are good for concurrency but does programming Python functionally really help with concurrency?
La risposta più quotata, di Alex, è lunga e non riassumibile. E mi sembra che non sia tanto positiva. Io sono per beardedprojamz (la terza): I have to say that too much ‘bandwagoning’ toward OO or functional could lead toward missing elegant solutions.

Ecco, adesso il post sembra ridursi a poca cosa, molto meno di quello che lascia intravedere il titolo. Colpa mia lo ammetto. Ma concludo lo stesso con come la penso, una cosa scontata.
Se rileggo la definizione riportata all’inizio e mi accontento di cose possibili di quelle che riesco a fare anch’io posso arrivare al compromesso di avere funzioni FP (ecco, qui avrei dovuto dire funzioni funzionali) dove possibile, che fanno una sola cosa, senza effetti collaterali, non usano variabili globali (OK, è lo stesso di prima ma così mi capisco), in modo possibilmente efficiente. E che sono facili da capire dagli umani (pensate alla manutenzione). Anche quelli come me che arrivano solo fino a un certo punto (sapete ho cominciato con il Fortran (ma non ditelo a EWD)).

catAl di là di questo ambito non mi sembra che Python sia usabile. O sbaglio? :mrgreen:

Aggiornamento: sono stato precipitoso e pasticcione (assay!). Mi sono dimenticato che avevo materiaale qui nel blog (roba del prof Lipari (rockz)), è passato un po’ di tempo e poi –OK, niente scuse :oops: :cry: :evil:
Ecco un paio di link:

Poi forse continuo, tentando di rimediare :mrgreen:

Risorse Python

python-logoUn commento dell’amico Flavio, the Man from Mars (da quando se n’è andato Marte è l’unico pianeta conosciuto abitato interamente da robots) mi fa una domanda impegnativa, qui:

volendo imparare il Python 3.x, la risorsa (libro, pdf, web) definitiva ed unica che mi consigli di seguire

Mica facile. Anzi, il contrario. Vi faccio un esempio metaforico di una cosa che avete forse già vissuto tutti quanti, probabilmente più e più volte.
Ma prima un avvertimento, un disclaimer: non sono responsabile in alcun modo di eventuali effetti collaterali (side effects) e/o conseguenze immediate, future e protratte nel tempo. Questo va inteso virtualmente, un Gedankenexperiment, nèh!
OK! allora immaginate di entrare in una pasticceria. Ecco, capito? Mica è facile. Nel senso che come si fa a limitarsi a uno, o due, o –ok, QED.

In ogni caso un PDF disponibile liberamente sul web che mi sembra buono è Think Python – How to Think Like a Computer Scientist di Allen B. Downey.
Giù in fondo c’è l’URL per la versione 3.x (versione adattata da Michael Kart) in PDF.
Mi sembra che si possa partire da lì.

Poi naturalmente –avete presente la metafora della pasticceria?– scoprirete che Ce n’est qu’un début, quindi aggiungo un po’ di roba.
Intanto la documentazione sul sito ufficiale di Python, qui: Python 3.4.3 documentation, trovate l’elenco di altre risorse, tante. E quelle raccomandate da loro.
Ci sono i corsi online, per esempio Codecademy, elementare e versione 2.x (è ancora la prevalente, anche se sono d’accordo per insistere con la 3) oppure qui Centre for Education in Mathematics and Computing at the University of Waterloo, 3.x ma molto basico, un assaggino.
Sempre sui corsi online c’è una discussione su Quora: Which online Python course is the best?
C’è un Wikibook: Python Programming, 2-x con indicazioni variazioni 3.x, sembra bello.
Un altro testo vecchio ma usabile, anche questo con parecchi link è Dive Into Python. Come mi fa notare Stefania nei commenti c’è anche la versione per 3.x: Dive Into Python 3.
Una comunità pythonista su G+.
Infine una cosa che ho scoperto sono ultimamente: ZEEF – Find information through people, nel nosto caso Python by Alan Richmond.
Trovate tante cose, anzi avrei potuto rispondere a Flavio, the MfM, comunicandogli solo questo link (ma il mio blog ne avrebbe sofferto). Per esempio utilissimo il CheatSheet e le espressioni regolari e millemila cose ancora.

Due cose ancora:

  • ci sarebbe tutto il discorso di NumPy/SciPy –prossimamente forse;
  • sì, ho problemi di peso.

Mission-Accomplished

:mrgreen:

Lo dice anche Nature: Python

Illustration by the Project Twins

Illustration by the Project Twins

OK, sto scrivendo un altro post ma questo devo segnalarvelo assolutamente. Non perché dica una cosa nuova, anzi dice quello che io sto dicendo da una ventina d’anni, anche sul blog (ma da meno tempo, non è così vecchio). Ma un conto è se lo dico io (me) un altro se compare su Nature.
Esamina il caso di Adina Howe, assistant professor of agricultural and biosystems engineering. Non è una programmatrice, non ha fatto informatica ma ingegneria ambientale. Ma programmare è importante. E sapete cosa dice? Trovate tutto qui: Programming: Pick up Python.

Da oggi manderò a questo post parecchi (non solo MATLABer), mi sa –ritenetevi avvisati nèh! :mrgreen:

E non manca un commento che rimarca la superiorità della programmazione funzionale, uhmmm:wink:

Python è impazzito!! (oppure no)

Picture 1

Girovagando per Facebook ( .. ) mi imbatto in un post: “ehi, qual è il risultato di (-5%4) in python??”

E che sarà? -1 mi dico io.

Invece python sbaglia, e toh! sbaglia anche google, mentre la calcolatrice di windows restituisce correttamente -1 e così anche, riporto fedelmente dal thread, “every programming language”.

Ce n’è abbastanza per porsi qualche domanda e verificare come stanno le cose, e capire se veramente qualcuno sbaglia e qualcun altro no.

Istantanea - 24012015 - 18:22:57

Stiamo parlando dell’operazione di “modulo”, che in informatica è definita come resto r della divisione intera tra due numeri a e b:

a/b=q  con resto  r

tali che b*q+r=a con 0 \leq r <b.

Se a  e b sono entrambi numeri naturali (interi positivi) tutti i linguaggi concordano: 5 modulo 4, o 5%4, restituisce 1. Il risultato della divisione, cioè 1.25 viene arrotondato verso il basso (“floor”) ad 1 ed il resto della divisione risulta 1.

Le cose cambiano se uno dei due termini è negativo: -5/4 restituisce -1.25. Se arrotondo ancora verso lo zero, non compio più un’operazione “floor” ma “ceiling”, cioè arrotondo verso l’alto q e gli assegno valore -1:

q=-1 \Rightarrow r=-1 ed otteniamo ciò che ci aspettiamo istintivamente e che restituisce un compilatore C.

Abbiamo però perso la condizione su r, che deve essere rettificata introducendo un valore assoluto:

0 \leq |r| <b

Python (e google!) mantengono invece l’operazione “floor” ed arrotondano ancora -1.25 verso il basso, cioè verso l’infinito negativo, quindi a -2. Questo permette di lasciare a r il suo segno positivo ma restituisce un risultato meno intuitivo:

4*(-2) +r = -5  \Rightarrow r=3.

Beh, allora chi ha ragione? Entrambi, perché entrambe le definizioni di modulo sono accettate. La scelta di implementare l’una o l’altra dipende da chi definisce il linguaggio.

Ecco come Guido Van Rossum spiega la scelta di mantenere l’operazione “floor” in Python:

I matematici che si occupano di teoria dei numeri preferiscono questa soluzione (Wikipedia). In Python ho deciso di fare lo stesso perché esistono alcune applicazioni interessanti della funzione modulo nelle quali il segno di a è irrilevante.  Supponiamo di avere un “francobollo” POSIX, cioè una data espressa come numero di secondi trascorsi dal primo gennaio 1970, e di voler estrarre da esso l’ora del giorno. Siccome ci sono 24*3600 = 86400 secondi in un giorno, l’orario (espresso in secondi) è semplicemente il risultato dell’operazione t%86400. Se però ci troviamo con una data antecedente il 01/01/1970 abbiamo un operando negativo, e se eseguiamo l’operazione “modulo di 86400″ arrotondando verso lo zero otteniamo un risultato senza significato. Arrotondando verso il basso invece tutto torna a posto ed estraiamo l’ora corretta.

E perché non fa la stessa cosa anche il C? Lo spiega ancora Guido:

Probabilmente era l’hardware a non fare questa operazione quando il C è stato progettato. E l’hardware non faceva l’operazione perché i numeri negativi erano rappresentati all’epoca come  “segno” più “ampiezza”, invece delle due rappresentazioni “a complemento” utilizzate ai giorni nostri.

Bene, mi fermo qui. Mi rendo conto di aver messo molta, troppa carne al fuoco…

Qualche riferimento:

Project Euler – Una piccola intro

euler_portrait

Ok, ci sono libri e tutorial, ma per imparare a programmare bisogna .. programmare! Se poi la matematica vi appassiona e le sfide vi intrigano siete nel posto giusto ;)

Project Euler è un progetto nato nel 2001 da una “costola” di matschallenge.net e divenuto un progetto indipendente nel 2006.

Qui trovate una serie di quesiti matematici di difficoltà crescente sulle quali testare la vostra abilità di programmatori. Create il vostro account e, una volta risolto correttamente un problema, avete accesso alla relativa discussione dove si commentano le soluzioni.

Attenzione però: un buon algoritmo non si limita a funzionare, ma deve essere efficiente! Se il vostro PC ha impiegato mezza giornata (e 5000 Watt) per trovare il risultato significa che potete fare di meglio, e la discussione vi aiuterà a capire dove e come è possibile ottimizzare.

Siccome la competizione è il sale delle nostre esistenze, una delle prime cose che impareremo è come ottenere il tempo di esecuzione del codice per confrontarlo con gli altri; io programmo programmicchio in Python e vi regalo subito le istruzioni che generano il report:


import time

start_time = time.time()

#qui i vostri algoritmi

elapsed_time = time.time() - start_time

print(elapsed_time)

Ah, se siete persone serie e usate Linux potete usare in alternativa il comando bash time:

time /percorso/script -opzioni argomenti

Insomma scorrendo i problemi di Project Euler prendiamo confidenza con funzioni, loop, ricorsioni, liste, istruzioni condizionali e debug, poi impariamo (o rinfreschiamo la memoria su) tante belle meraviglie matematiche. Controindicazioni? Può causarvi insonnia, sapete com’è quando ci si diverte vero?

Un IDE per Python — PyCharm

BlogPostPicture_PyCharm4Solo una segnalazione, pare sia utile fare anche queste cose.
Anche se personalmente preferisco occuparmi di cose che –sembra– interessano solo me; prendi il post di ieri sul Lisp che finora ha accumulato 5 (cinque) visite :evil: OK, non sapete cosa vi perdete.
Dunque, tornando al dunque: c’è chi si lamenta che spesso nel mondo Linux manca un ambiente di sviluppo come si deve, tipo VisualStudio per M$Windows. In parte è vero, in parte solo colpa mia. Per me vanno benissimo Gedit (in effetti la versione 64 bit per Linux qualche bug ce l’ha; quella Windows anche), Geany (sì, c’è anche per Windows) e poco altro. Sono vecchio.
Uh! –e qui anticipo in parte la risposta all’amico itfs— mi sto scoprendo allergico anche a quelle cose troppo grosse, tipo Emacs (perdono RMS, non è come sembra, sappitelo o comunque fattene una ragione).
Quindi PyCharm, per Python. Tutto è nato da questo post, visto su Twitter (l’uccellino azzurro si dismostra sempre più indispensabile!): Announcing General Availability of PyCharm 4. Prima di subito Appena possibile sono andato sul sito, qui: The Most Intelligent Python IDE. Ho provato la versione free, Download PyCharm,  la Community Edition, OK, senza i componenti per il web, c’è per Windows. Fatto qualche piccola prova, sembra OK (in realtà ho solo assistito, su Windoze, certo non è VisualStudio ma vabeeene, dicono).

OK :wink: Adesso mi viene un dubbio: questo post riuscirà a battere il record del precedente?
Ma ho anche la risposta, anzi due: fregacazzi, direbbe Zerocalcare, chissene… dicono da queste parti. Forse :grin:

Rose e Python & ____

Lo so benissimo che dovrei occuparmi di quello che ho promesso (e prossimamente ci sarà anche itfs :grin:) ma intanto una segnalazione.
slUn blog che ho scoperto da poco, di Rose Ames, di cui so molto poco; è attiva su GitHub con diverse cose, tutte toste.

Siccome io sono un evangelista Python devo riproporvi Prime Time, fresco di giornata, su come si può usare seriamente il proprio ‘puter.

Devo pubblicarlo, anche se di mio ho aggiunto solo laa soppressione dell’a-capo. Ecco:

def numbers():
    i = 1
    while True:
        i += 1
        yield i

def make_filter(prime, prev_filter):
    while True:
        candidate = next(prev_filter)
        if candidate % prime != 0:
            yield candidate

def primes():
    pipeline = numbers()
    while True:
        next_prime = next(pipeline)
        pipeline = make_filter(next_prime, pipeline)
        yield next_prime

prime_generator = primes()
for i in range(100):
    print(next(prime_generator), end=" ")

pt

Voi intanto RSSatela, subito.

Divagazioni pythoniane: frazioni continue

Davvero non so come cominciare. Ma una rassicurazione prima di tutto: sto bene; e posso smettere quando voglio. Anzi mi sta già passando. Finisco il post e torno quello di sempre.
Ma intanto è meglio se vi racconto tutto.

SID-244-Revelli-S-800x800Recentemente mi sono preso una cotta di quelle toste per quel libro, ne ho parlato diffusamente nell’altro blog, quello più vario e meno serioso, diffusamente ma principalmente qui.
Dal libro sono passato al mio ing. preferito, Archimede e googlando sono capitato sul sito di un prof canadese di Parigi, Ilan Vardi e di lì alle frazioni continue.
Sì, completamente perso; tanto il ritardo è talmente tanto che cambia poco. Ecco le frazioni continue non le avevo mai considerate. Fino a oggi. Per esempio prendi π, si può approssimare così:

pi-vardi

E poi scriverlo in questo modo π ~= [3, 7, 15, 1, 292, ...]. E da questo tornare a calcolare il valore decimale. Adesso lo faccio, mi son detto. Ma c’è Google. E John D. Cook che ha già fatto tutto, ecco il suo post: Rational approximations to e.
John è davvero bravo, con piccolissime modifiche, sostituire pi a e (righe 2, 4 e 26) e il codice è pronto (pijdc.py):

from __future__ import division
from math import pi

pi_frac = [3, 7, 15, 1, 292, 1, 1, 1, 2, 1, 3, 1, 14, 2]

def display(n, d, exact):
    print n, d, n/d, n/d - exact

def approx(a, exact):
    # initialize the recurrence
    n0 = a[0]
    d0 = 1
    n1 = a[0]*a[1] + 1
    d1 = a[1]

    display(n0, d0, exact)
    display(n1, d1, exact)

    for x in a[2:]:
        n = x*n1 + n0 # numerator
        d = x*d1 + d0 # denominator
        display(n, d, exact)
        n1, n0 = n, n1
        d1, d0 = d, d1

approx(pi_frac, pi)

pijdc

Bello vero? Adesso uno la frazione continua potrebbe anche calcolarsela ma c’è il web. Sempre da John ecco OEIS.

Uh, c’è il sorgente per Mathematica: ContinuedFraction[Pi, 98], da provare. Il fatto è che Mathematica è onerosa, dovrei fare un salto al Poli, chiedere a una delle mie vittime … ma c’è un modo più semplice: WolframAlpha online.

mathe

Cosmico! Se fossi ricco Mathematica sarebbe mia!
Ma aspetta, c’è un clone free, devo riprendere Mathics, appena ho la macchina nuova e smaltisco l’arretrato…

Con Python attenti al tipo

turboDisperazione pythonistica. Alle volte per fare in fretta si perde un sacco di tempo. O forse sono io (in questo caso non proprio io) che manco di metodo. Adesso vi racconto di un problema di traduzione, riscrivere in Python un programmino semplice-semplice. Tanto semplice che si sono aperte due finestre dell’editor e si è tradotto letteralmente. Non ha funzionato. Eppure a mano, rifacendo i conti (lunghetti) del sorgente Python era tutto OK. Naturalmente non ho pensato subito che il problema è che Python è troppo intelligente e pretende di capire al volo quel che hai in mente. In questo caso il tipo di dato che gli stai passando.
Adesso vi racconto con un esempio minimo, se ci sono in giro distratti come me noi, forse può servire.
Nei dump del terminale che seguono sono in neretto le risposte di Python.


Python 2.7.6 (default, Mar 22 2014, 22:59:38) 
>>> d = input("dato: ")
dato: 12
>>> d
12
>>> print d
12
>>> type(d)
<type 'int'>
>>> d = float(d)
>>> d
12.0

Naturalmente si può scrivere:


>>> d = float(input("dato: "))
dato: 12
>>> d
12.0

Fin qui tutto bene, il dato può essere letto da file. Vediamo cosa succede elaborando:


>>> d = input("dato: ")
dato: 12
>>> r = 100 / d
>>> r
8
>>> s = 10 / d
>>> s
0
>>> import math
>>> math.log(r)
2.0794415416798357
>>> math.log(s)
Traceback (most recent call last):
  File "", line 1, in 
ValueError: math domain error

Primo problema: con la versione 2.x “/” effettua la divisione tra interi e il risultato forse non è quello voluto, in questo caso il logaritmo naturale, sbagliato nel primo caso e non definito nel secondo.
C’è un ulteriore problema: da parecchio tempo (diciamo sempre) di Pyhton coesistono due versioni, la 2.x e la 3.x. Per tantissime ragioni (oltre alla pigrizia) non si è deciso quale adottare una volta per tutte. Oltretutto c’è il fatto che qualche modulo (wx) non esiste per la 3.x.
Le stesse operazioni di prima con la nuova versione:


Python 3.4.0 (default, Apr 11 2014, 13:05:18) 
>>> d = input("dato: ")
dato: 12
>>> d
'12'
>>> type(d)
<class 'str'>
>>> d = float(d)
>>> d
12.0
>>> r = 100 / d
>>> r
8.333333333333334
>>> s = 10 / d
>>> s
0.8333333333333334
>>> print d
  File "", line 1
    print d
          ^
SyntaxError: invalid syntax
>>> print(d)
12.0
>>> import math
>>> math.log(r)
2.120263536200091
>>> math.log(s)
-0.1823215567939546

OOPS! sono cambiate parecchie cose:

  • input() restituisce una stringa, questo rende obbligatorio il cast non solo per i float ma anche per gli int, peraltro il codice è compatibile per le due versioni;
  • /” restituisce sempre un float, in questo caso i valori sono quelli previsti ma è da valutare con attenzione (esiste “//” per la divisione tra interi);
  • print() è adesso una funzione, non un’istruzione come nel 2.

In realtà sono problemi ampiamente noti, tanto che esistono i meccanismi per conviverci, ecco per print:


Python 2.7.6 (default, Mar 22 2014, 22:59:38) 
>>> from __future__ import print_function
>>> print d
  File "", line 1
    print d
          ^
SyntaxError: invalid syntax
>>> print(d)
12.0

Importando print() dal modulo __future__ la versione 2 si comporta come la 3; e la 3:


Python 3.4.0 (default, Apr 11 2014, 13:05:18) 
>>> from __future__ import print_function
>>> d = 12.0
>>> print d
  File "", line 1
    print d
          ^
SyntaxError: invalid syntax
>>> print(d)
12.0

OK, non si lamenta di un istruzione inutile. E per il resto? Fare più attenzione a quello che si fa; e testare tutto.
2to3

I decoratori in Python

python-logoPython è il mio linguaggio di programmazione preferito. OK, ce ne sono anche parecchi altri ma in certi casi è il migliore. Secondo me naturalmente. È un po’ come il Basic di una volta; poi quando il gioco si fa duro…
Naturalmente esistono alternative, ne ho parlato in passato e probabilmente ne riparlerò presto. Ma oggi Python.
Python, per fare davvero il Basic contemporaneo, deve risultare semplice, usabile anche da chi non smanetta a tempo pieno.
Ogni tanto però salta fuori qualcosa che scombina tutto. Per esempio l’eterna transizione da 2.x a 3.x, in confronto Mosè è stato velocissimo.
Oppure i decoratori. Argomento tornato attuale con questo tweet:

pytime

Jake Vanderplas è un postdoc che si occupa di cose stellari e di Python. Dovreste seguirlo, per Python almeno, qui: Pythonic Perambulations.
Appena visto il cinguettio mi sono detto che il momento di affrontare i decoratori era arrivato. Subito. Poi, OK, sono passati giorni ma adesso ci sono. E non metto neanche troppa enfasi sul fatto che io non li uso e non mi piacciono. Ma ogni tanto saltano fuori e allora…

L’esempio di Jake è ottimo, vediamo:

import contextlib, time

@contextlib.contextmanager
def timeit():
	t = time.time()
	yield
	print time.time() - t

def calcola(n):
	s = 0
	for c in range(1, n):
		s += c**2
	return s

with timeit():
	print calcola(100)

Senza il decoratore (riga 3) ottengo un errore:

senza

Invece tutto funziona con:

con

Notare che il messaggio d’errore  è criptico e non dice dove capita (sì ma bisogna pensarci su un po’).

OK, cos’è un decoratore?
Un decoratore è una normale funzione che modifica un’altra funzione. Quando si usa un decoratore, Python passa la funzione da decorare al decoratore, e la sostituisce con il risultato. (Sì, copiato da qui).

Quindi tornando all’esempio di Jake la funzione timeit() viene passata a contextmanager() del modulo contextlib. Trovate tutto qui: contextlib – Context manager utilities.

Ecco. Questo potrebbe bastare per: 1) confermare l’idea che i decoratori siano roba da matti; oppure 2) argomento da approfondire, con un esempio sensato, sviluppato in dettaglio. Credo che seguirò la seconda alternativa anche perché altrimenti il post sarebbe troppo breve.

Però aspetta: non riuscirei a fare meglio di Bancaldo, qui: Python: decoratori per programmatori di coccio.

Uh! due cose: 1) Bancaldo l’avevo perso nel passaggio da GReader a Feedly, rimediato adesso; 2) nel post trovate anche quando conviene usarli:

# Dove e quando usare i decoratori nella realtà?
Beh un esempio pratico è quando abbiamo necessità di modificare una funzione di una libreria esterna. Siccome non è buona cosa modificare le funzioni di librerie esterne, si lavora su di esse con i decoratori.

E con questo davvero risulta che il post è venuto molto diverso da come pensavo. Intanto salta fuori che basta googlare e spesso si trova esattamente quello che serve. Spesso in italiano, come in questo caso; anche se come scusa di trovare solo roba in inglese la trovo sempre più irritante (sto peggiorando, lo so).

Chi poi volesse tutto lo spiegone, completo dettagliato, lungo, di quelli che TL;DR c’è il Wiki di Python: PythonDecorators.

Anzi la prossima volta che mi fanno questa domanda o una simile li mando subito lì: Python Wiki rockz :razz:

Iscriviti

Ricevi al tuo indirizzo email tutti i nuovi post del sito.

Unisciti agli altri 85 follower