human
Solve the following python programming problem given the following code:
# -*- coding: utf-8 -*-

# This is hello_who_3.py
import sys                            # <-- importo un modulo

def compose_hello(who, force=False):   # <-- valore di default
    """
    Get the hello message.
    """ 
    try:                                     # <-- gestione eccezioni `Duck Typing`
        message = "Hello " + who + "!"
    except TypeError:                       # <-- eccezione specifica
    # except TypeError as e:                       # <-- eccezione specifica su parametro e
        print("[WARNING] Il parametro `who` dovrebbe essere una stringa")
        if force:                            # <-- controllo "if"
            message = "Hello {}!".format(who)
        else:
            raise                            # <-- solleva eccezione originale
    except Exception:
        print("Verificatasi eccezione non prevista")
    else:
        print("nessuna eccezione")
    finally:
        print("Bye")
    
    return message

def hello(who='world'):               # <-- valore di default
    print(compose_hello(who))

if __name__ == "__main__":
    hello("mamma")

hello("pippo")

hello(1)

ret = compose_hello(1, force=True)
print("Ha composto {}".format(ret))

try:
    hello(1)
except TypeError as e:
    print("{}: {}".format(type(e).__name__, e))
    print("Riprova")
Given the above code, generate some markdown instructions for it.
assistant
#Here is the Python program you requested.

Funzioni con parametri posizionali, nominali, e arbitrari
Una funzione si definisce con def &lt;nomefunzione&gt;([parametri]) dove i parametri possono essere:

posizionali. Ad es: def hello(who)
nominali. Ad es: def hello(who='') o who=None o who='default'
entrambi, ma i nominali devono essere messi dopo i posizionali. Ad es: def hello(who, say="How are you?")
arbitrari sia posizionali con il simbolo * o nominali con **. Come convenzione si utilizzano i nomi args e kw o kwargs. Ad es: def hello(who, say="How are you?", *args, **kw)

I simboli * e ** indicano rispettivamente la rappresentazione di una lista come una sequenza di elementi, e di un dizionario come una sequenza di parametri &lt;chiave&gt;=&lt;valore&gt;
Scope delle variabili
http://www.saltycrane.com/blog/2008/01/python-variable-scope-notes/
e ricordatevi che:
for i in [1,2,3]:
      print(i)
  print("Sono fuori dal ciclo e posso vedere che i={}".format(i))
Namespace
I namespace in python sono raccoglitori di nomi e posson essere impliciti o espliciti. Sono impliciti lo spazio dei nomi __builtin__ e __main__. Sono espliciti, le classi, gli oggetti, le funzioni e in particolare i moduli.
Posso importare un modulo che mi va a costituire un namespace con import &lt;nomemodulo&gt; e accedere a tutti i simboli top-level inseriti nel modulo come &lt;nomemodulo&gt;.&lt;simbolo&gt;.
L'importazione di simboli singoli all'interno di un modulo in un altro namespace si può fare con from &lt;nomemodulo&gt; import &lt;simbolo&gt;. Quello che non si dovrebbe fare è importare tutti i simboli di un modulo dentro un altro nella forma: from &lt;nomemodulo&gt; import *. Non fatelo, a meno che non strettamente necessario.
Stack delle eccezioni e loro gestione
Lo stack delle eccezioni builtin, ossia già comprese nel linguaggio python sono al link: https://docs.python.org/2/library/exceptions.html#exception-hierarchy
Derivando da essere facilmente se ne possono definire di proprie.
La gestione delle eccezioni avviene in blocchi:
try:
    ...
except [eccezione] [as...