6. Moduli
*********

Se chiudi l'interprete Python e lo riapri, le definizioni che hai
fatto (funzioni e variabili) vengono perse. Pertanto, se vuoi scrivere
un programma un po' più lungo, è meglio usare un editor di testo per
preparare l'input per l'interprete e eseguirlo con quel file come
input. Questo è conosciuto come creare uno *script*. Man mano che il
tuo programma diventa più lungo, potresti volerlo dividere in diversi
file per una manutenzione più facile. Potresti anche voler usare una
funzione utile che hai scritto in diversi programmi senza copiarne la
definizione in ciascun programma.

Per supportare questo, Python ha un modo per mettere definizioni in un
file e usarle in uno script o in un'istanza interattiva
dell'interprete. Tale file è chiamato un *modulo*; le definizioni di
un modulo possono essere *importate* in altri moduli o nel *modulo
principale* (la collezione di variabili a cui hai accesso in uno
script eseguito al livello superiore e in modalità calcolatrice).

Un modulo è un file contenente definizioni e istruzioni Python. Il
nome del file è il nome del modulo con il suffisso ".py" aggiunto.
All'interno di un modulo, il nome del modulo (come stringa) è
disponibile come valore della variabile globale "__name__". Ad
esempio, usa il tuo editor di testo preferito per creare un file
chiamato "fibo.py" nella directory corrente con il seguente contenuto:

   # Fibonacci numbers module

   def fib(n):
       """Write Fibonacci series up to n."""
       a, b = 0, 1
       while a < n:
           print(a, end=' ')
           a, b = b, a+b
       print()

   def fib2(n):
       """Return Fibonacci series up to n."""
       result = []
       a, b = 0, 1
       while a < n:
           result.append(a)
           a, b = b, a+b
       return result

Ora entra nell'interprete Python e importa questo modulo con il
seguente comando:

   >>> import fibo

Questo non aggiunge i nomi delle funzioni definite in "fibo"
direttamente all'attuale *namespace* (vedi Visibilità e spazi dei nomi
in Python per maggiori dettagli); aggiunge solo il nome del modulo
"fibo" lì. Utilizzando il nome del modulo puoi accedere alle funzioni:

   >>> fibo.fib(1000)
   0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
   >>> fibo.fib2(100)
   [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
   >>> fibo.__name__
   'fibo'

Se intendi usare una funzione spesso puoi assegnarla a un nome locale:

   >>> fib = fibo.fib
   >>> fib(500)
   0 1 1 2 3 5 8 13 21 34 55 89 144 233 377


6.1. Più sui Moduli
===================

Un modulo può contenere istruzioni eseguibili così come definizioni di
funzioni. Queste istruzioni sono intese per inizializzare il modulo.
Sono eseguite solo la *prima* volta che il nome del modulo viene
incontrato in un'istruzione d'importazione. [1] (Sono anche eseguite
se il file è eseguito come script.)

Ogni modulo ha il proprio namespace privato, che è utilizzato come il
namespace globale da tutte le funzioni definite nel modulo. Pertanto,
l'autore di un modulo può usare variabili globali nel modulo senza
preoccuparsi di collisioni accidentali con le variabili globali di un
utente. D'altra parte, se sai quello che stai facendo puoi toccare le
variabili globali di un modulo con la stessa notazione utilizzata per
riferirsi alle sue funzioni, "modname.itemname".

I moduli possono importare altri moduli. È consuetudine, ma non
obbligatorio, posizionare tutte le istruzioni "import" all'inizio di
un modulo (o script, se è per questo). I nomi dei moduli importati, se
posizionati a livello superiore di un modulo (fuori da qualsiasi
funzione o classe), sono aggiunti al namespace globale del modulo.

Esiste una variante dell'istruzione "import" che importa nomi da un
modulo direttamente nel namespace del modulo importante. Ad esempio:

   >>> from fibo import fib, fib2
   >>> fib(500)
   0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

Questo non introduce il nome del modulo da cui provengono le
importazioni nel namespace locale (quindi nell'esempio, "fibo" non è
definito).

Esiste anche una variante per importare tutti i nomi che un modulo
definisce:

   >>> from fibo import *
   >>> fib(500)
   0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

Questo importa tutti i nomi eccetto quelli che iniziano con un
underscore ("_"). Nella maggior parte dei casi i programmatori Python
non utilizzano questa funzione poiché introduce un insieme sconosciuto
di nomi nell'interprete, nascondendo possibilmente alcune cose che hai
già definito.

Nota che in generale la pratica di importare "*" da un modulo o
pacchetto è disapprovata, poiché spesso causa codice poco leggibile.
Tuttavia, è accettabile usarla per risparmiare battitura nelle
sessioni interattive.

Se il nome del modulo è seguito da "as", allora il nome che segue "as"
è legato direttamente al modulo importato.

   >>> import fibo as fib
   >>> fib.fib(500)
   0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

Questo importa effettivamente il modulo nello stesso modo in cui lo
farebbe "import fibo", con l'unica differenza che sarà disponibile
come "fib".

Può anche essere utilizzato quando si utilizza "from" con effetti
simili:

   >>> from fibo import fib as fibonacci
   >>> fibonacci(500)
   0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

Nota:

  Per ragioni di efficienza, ogni modulo viene importato una sola
  volta per sessione dell'interprete. Pertanto, se cambi i tuoi
  moduli, devi riavviare l'interprete -- o, se è solo un modulo che
  vuoi testare interattivamente, usa "importlib.reload()", es. "import
  importlib; importlib.reload(modulename)".


6.1.1. Esecuzione di moduli come script
---------------------------------------

Quando esegui un modulo Python con

   python fibo.py <arguments>

il codice nel modulo sarà eseguito, proprio come se lo avessi
importato, ma con "__name__" impostato su ""__main__"". Ciò significa
che aggiungendo questo codice alla fine del tuo modulo:

   if __name__ == "__main__":
       import sys
       fib(int(sys.argv[1]))

puoi rendere il file utilizzabile sia come script che come modulo
importabile, poiché il codice che analizza la linea di comando viene
eseguito solo se il modulo è eseguito come file "principale":

   $ python fibo.py 50
   0 1 1 2 3 5 8 13 21 34

Se il modulo è importato, il codice non viene eseguito:

   >>> import fibo
   >>>

Questo è spesso usato sia per fornire un'interfaccia utente comoda a
un modulo, sia per scopi di test (eseguire il modulo come script
esegue una suite di test).


6.1.2. Il percorso di ricerca del modulo
----------------------------------------

Quando un modulo chiamato "spam" è importato, l'interprete cerca prima
un modulo built-in con quel nome. Questi nomi di moduli sono elencati
in "sys.builtin_module_names". Se non viene trovato, allora cerca un
file chiamato "spam.py" in una lista di directory data dalla variabile
"sys.path". "sys.path" è inizializzata da queste posizioni:

* La directory contenente lo script di input (o la directory corrente
  quando non è specificato alcun file).

* "PYTHONPATH" (una lista di nomi di directory, con la stessa sintassi
  della variabile di shell "PATH").

* Il valore predefinito dipendente dall'installazione (per convenzione
  include una directory "site-packages", gestita dal modulo "site").

Maggiori dettagli sono disponibili in The initialization of the
sys.path module search path.

Nota:

  Su file system che supportano i collegamenti simbolici, la directory
  contenente lo script di input viene calcolata dopo che il
  collegamento simbolico è stato seguito. In altre parole la directory
  contenente il collegamento simbolico **non** è aggiunta al percorso
  di ricerca del modulo.

Dopo l'inizializzazione, i programmi Python possono modificare
"sys.path". La directory contenente lo script in esecuzione è
posizionata all'inizio del percorso di ricerca, davanti al percorso
della libreria standard. Ciò significa che gli script in quella
directory saranno caricati invece dei moduli con lo stesso nome nella
directory della libreria. Questo è un errore a meno che la
sostituzione non sia intenzionale. Vedi la sezione Moduli Standard per
maggiori informazioni.


6.1.3. File Python "compilati"
------------------------------

Per velocizzare il caricamento dei moduli, Python memorizza nella
cache la versione compilata di ciascun modulo nella directory
"__pycache__" sotto il nome "module.*version*.pyc", dove la versione
codifica il formato del file compilato; contiene generalmente il
numero di versione di Python. Ad esempio, nella versione CPython 3.3,
la versione compilata di spam.py verrebbe memorizzata nella cache come
"__pycache__/spam.cpython-33.pyc". Questa convenzione di denominazione
permette ai moduli compilati di versioni diverse e rilasci diversi di
Python di coesistere.

Python controlla la data di modifica della sorgente rispetto alla
versione compilata per vedere se è obsoleta e deve essere ricompilata.
Questo è un processo completamente automatico. Inoltre, i moduli
compilati sono indipendenti dalla piattaforma, quindi la stessa
libreria può essere condivisa tra sistemi con diverse architetture.

Python non controlla la cache in due circostanze. Primo, ricompila
sempre e non memorizza il risultato per il modulo caricato
direttamente dalla linea di comando. Secondo, non controlla la cache
se non esiste il modulo sorgente. Per supportare una distribuzione
senza sorgente (solo compilata), il modulo compilato deve essere nella
directory sorgente e non deve esserci un modulo sorgente.

Alcuni consigli per esperti:

* Puoi usare le opzioni "-O" o "-OO" sul comando Python per ridurre la
  dimensione di un modulo compilato. L'opzione "-O" rimuove le
  istruzioni assert, l'opzione "-OO" rimuove sia le istruzioni assert
  che le stringhe __doc__. Poiché alcuni programmi possono fare
  affidamento su queste, dovresti usare questa opzione solo se sai
  quello che stai facendo. I moduli "ottimizzati" hanno un tag "opt-"
  e sono solitamente più piccoli. I futuri rilasci possono cambiare
  gli effetti dell'ottimizzazione.

* Un programma non gira più velocemente quando è letto da un file
  ".pyc" rispetto a quando è letto da un file ".py"; l'unica cosa che
  è più veloce nei file ".pyc" è la velocità con cui vengono caricati.

* Il modulo "compileall" può creare file .pyc per tutti i moduli in
  una directory.

* Ci sono maggiori dettagli su questo processo, incluso un diagramma
  di flusso delle decisioni, in **PEP 3147**.


6.2. Moduli Standard
====================

Python viene fornito con una libreria di moduli standard, descritta in
un documento separato, il Python Library Reference ("Library
Reference" da qui in avanti). Alcuni moduli sono incorporati
nell'interprete; questi forniscono accesso a operazioni che non fanno
parte del core del linguaggio ma sono comunque incorporate, sia per
efficienza che per fornire accesso a primitive del sistema operativo
come le chiamate di sistema. Il set di tali moduli è un'opzione di
configurazione che dipende anche dalla piattaforma sottostante. Ad
esempio, il modulo "winreg" è fornito solo sui sistemi Windows. Un
particolare modulo merita attenzione: "sys", che è incorporato in ogni
interprete Python. Le variabili "sys.ps1" e "sys.ps2" definiscono le
stringhe usate come prompt primario e secondario:

   >>> import sys
   >>> sys.ps1
   '>>> '
   >>> sys.ps2
   '... '
   >>> sys.ps1 = 'C> '
   C> print('Yuck!')
   Yuck!
   C>

Queste due variabili sono definite solo se l'interprete è in modalità
interattiva.

La variabile "sys.path" è una lista di stringhe che determina il
percorso di ricerca dell'interprete per i moduli. È inizializzata a un
percorso predefinito preso dalla variabile di ambiente "PYTHONPATH", o
da un predefinito incorporato se "PYTHONPATH" non è impostato. Puoi
modificarla usando le operazioni standard delle liste:

   >>> import sys
   >>> sys.path.append('/ufs/guido/lib/python')


6.3. La funzione "dir()"
========================

La funzione built-in "dir()" è usata per scoprire quali nomi definisce
un modulo. Restituisce una lista ordinata di stringhe:

   >>> import fibo, sys
   >>> dir(fibo)
   ['__name__', 'fib', 'fib2']
   >>> dir(sys)
   ['__breakpointhook__', '__displayhook__', '__doc__', '__excepthook__',
    '__interactivehook__', '__loader__', '__name__', '__package__', '__spec__',
    '__stderr__', '__stdin__', '__stdout__', '__unraisablehook__',
    '_clear_type_cache', '_current_frames', '_debugmallocstats', '_framework',
    '_getframe', '_git', '_home', '_xoptions', 'abiflags', 'addaudithook',
    'api_version', 'argv', 'audit', 'base_exec_prefix', 'base_prefix',
    'breakpointhook', 'builtin_module_names', 'byteorder', 'call_tracing',
    'callstats', 'copyright', 'displayhook', 'dont_write_bytecode', 'exc_info',
    'excepthook', 'exec_prefix', 'executable', 'exit', 'flags', 'float_info',
    'float_repr_style', 'get_asyncgen_hooks', 'get_coroutine_origin_tracking_depth',
    'getallocatedblocks', 'getdefaultencoding', 'getdlopenflags',
    'getfilesystemencodeerrors', 'getfilesystemencoding', 'getprofile',
    'getrecursionlimit', 'getrefcount', 'getsizeof', 'getswitchinterval',
    'gettrace', 'hash_info', 'hexversion', 'implementation', 'int_info',
    'intern', 'is_finalizing', 'last_traceback', 'last_type', 'last_value',
    'maxsize', 'maxunicode', 'meta_path', 'modules', 'path', 'path_hooks',
    'path_importer_cache', 'platform', 'prefix', 'ps1', 'ps2', 'pycache_prefix',
    'set_asyncgen_hooks', 'set_coroutine_origin_tracking_depth', 'setdlopenflags',
    'setprofile', 'setrecursionlimit', 'setswitchinterval', 'settrace', 'stderr',
    'stdin', 'stdout', 'thread_info', 'unraisablehook', 'version', 'version_info',
    'warnoptions']

Senza argomenti, "dir()" elenca i nomi che hai definito attualmente:

   >>> a = [1, 2, 3, 4, 5]
   >>> import fibo
   >>> fib = fibo.fib
   >>> dir()
   ['__builtins__', '__name__', 'a', 'fib', 'fibo', 'sys']

Nota che elenca tutti i tipi di nomi: variabili, moduli, funzioni,
ecc.

"dir()" non elenca i nomi delle funzioni e variabili built-in. Se vuoi
una lista di questi, sono definiti nel modulo standard "builtins":

   >>> import builtins
   >>> dir(builtins)
   ['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException',
    'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning',
    'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError',
    'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning',
    'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False',
    'FileExistsError', 'FileNotFoundError', 'FloatingPointError',
    'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError',
    'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError',
    'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError',
    'MemoryError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented',
    'NotImplementedError', 'OSError', 'OverflowError',
    'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError',
    'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning',
    'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError',
    'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError',
    'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError',
    'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning',
    'ValueError', 'Warning', 'ZeroDivisionError', '_', '__build_class__',
    '__debug__', '__doc__', '__import__', '__name__', '__package__', 'abs',
    'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', 'callable',
    'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits',
    'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit',
    'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr',
    'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass',
    'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview',
    'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property',
    'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice',
    'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars',
    'zip']


6.4. Pacchetti
==============

I pacchetti sono un modo di strutturare il namespace dei moduli di
Python usando "nomi di moduli puntati". Ad esempio, il nome del modulo
"A.B" designa un sottomodulo chiamato "B" in un pacchetto chiamato
"A". Proprio come l'uso dei moduli salva gli autori di diversi moduli
dal preoccuparsi dei nomi delle variabili globali degli altri, l'uso
dei nomi di moduli puntati salva gli autori di pacchetti multi-modulo
come NumPy o Pillow dal preoccuparsi dei nomi dei moduli degli altri.

Supponiamo che tu voglia progettare una collezione di moduli (un
"pacchetto") per la gestione uniforme dei file audio e dei dati audio.
Ci sono molti formati di file audio diversi (di solito riconosciuti
dalla loro estensione, ad esempio: ".wav", ".aiff", ".au"), quindi
potresti aver bisogno di creare e mantenere una collezione crescente
di moduli per la conversione tra i vari formati di file. Ci sono anche
molte operazioni diverse che potresti voler eseguire sui dati audio
(come il mixaggio, l'aggiunta di eco, l'applicazione di una funzione
equalizzatrice, la creazione di un effetto stereo artificiale),
quindi, in aggiunta, scriverai una serie interminabile di moduli per
eseguire queste operazioni. Ecco una possibile struttura per il tuo
pacchetto (espressa in termini di filesystem gerarchico):

   sound/                          Top-level package
         __init__.py               Initialize the sound package
         formats/                  Subpackage for file format conversions
                 __init__.py
                 wavread.py
                 wavwrite.py
                 aiffread.py
                 aiffwrite.py
                 auread.py
                 auwrite.py
                 ...
         effects/                  Subpackage for sound effects
                 __init__.py
                 echo.py
                 surround.py
                 reverse.py
                 ...
         filters/                  Subpackage for filters
                 __init__.py
                 equalizer.py
                 vocoder.py
                 karaoke.py
                 ...

Quando importa il pacchetto, Python cerca nelle directory su
"sys.path" cercando la sottodirectory del pacchetto.

I file "__init__.py" sono richiesti per fare in modo che Python tratti
le directory contenenti il file come pacchetti (a meno che non si
utilizzi un *namespace package*, una funzionalità relativamente
avanzata). Questo impedisce alle directory con un nome comune, come
"string", di nascondere inavvertitamente moduli validi che si trovano
più avanti nel percorso di ricerca del modulo. Nel caso più semplice,
"__init__.py" può essere solo un file vuoto, ma può anche eseguire
codice di inizializzazione per il pacchetto o impostare la variabile
"__all__", descritta più avanti.

Gli utenti del pacchetto possono importare moduli individuali dal
pacchetto, ad esempio:

   import sound.effects.echo

Questo carica il sottomodulo "sound.effects.echo". Deve essere
referenziato con il suo nome completo.:

   sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)

Un modo alternativo di importare il sottomodulo è:

   from sound.effects import echo

Questo carica anche il sottomodulo "echo", e lo rende disponibile
senza il prefisso del pacchetto, quindi può essere usato come segue:

   echo.echofilter(input, output, delay=0.7, atten=4)

Un'ulteriore variazione è importare direttamente la funzione o la
variabile desiderata:

   from sound.effects.echo import echofilter

Ancora una volta, questo carica il sottomodulo "echo", ma rende
direttamente disponibile la sua funzione "echofilter()":

   echofilter(input, output, delay=0.7, atten=4)

Nota che quando usi "from package import item", l'elemento può essere
un sottomodulo (o sottopacchetto) del pacchetto, o qualche altro nome
definito nel pacchetto, come una funzione, classe o variabile.
L'istruzione "import" testa prima se l'elemento è definito nel
pacchetto; se non lo è, assume che sia un modulo e tenta di caricarlo.
Se non riesce a trovarlo, viene sollevata un'eccezione "ImportError".

Al contrario, quando usi una sintassi come "import
item.subitem.subsubitem", ciascun elemento tranne l'ultimo deve essere
un pacchetto; l'ultimo elemento può essere un modulo o un pacchetto ma
non può essere una classe, funzione o variabile definita nell'elemento
precedente.


6.4.1. Importare * Da un Pacchetto
----------------------------------

Ora cosa succede quando l'utente scrive "from sound.effects import *"?
Idealmente, si spera che questo vada in qualche modo nel filesystem,
trovi quali sottomoduli sono presenti nel pacchetto e li importi
tutti. Questo potrebbe richiedere molto tempo e l'importazione di
sottomoduli potrebbe avere effetti collaterali indesiderati che
dovrebbero accadere solo quando il sottomodulo viene importato
esplicitamente.

L'unica soluzione è che l'autore del pacchetto fornisca un indice
esplicito del pacchetto. L'istruzione "import" utilizza la seguente
convenzione: se il codice di "__init__.py" di un pacchetto definisce
una lista denominata "__all__", essa è considerata la lista dei nomi
dei moduli che dovrebbero essere importati quando si incontra "from
package import *". È compito dell'autore del pacchetto mantenere
aggiornata questa lista quando viene rilasciata una nuova versione del
pacchetto. Gli autori dei pacchetti possono anche decidere di non
supportarla, se non vedono un'utilità per l'importazione * dal loro
pacchetto. Ad esempio, il file "sound/effects/__init__.py" potrebbe
contenere il seguente codice:

   __all__ = ["echo", "surround", "reverse"]

Questo significherebbe che "from sound.effects import *" importerebbe
i tre sottomoduli denominati del pacchetto "sound.effects".

Tieni presente che i sottomoduli potrebbero essere ombreggiati da nomi
definiti localmente. Ad esempio, se aggiungi una funzione "reverse" al
file "sound/effects/__init__.py", "from sound.effects import *"
importerebbe solo i due sottomoduli "echo" e "surround", ma *non* il
sottomodulo "reverse", perché è oscurato dalla funzione "reverse"
definita localmente.:

   __all__ = [
       "echo",      # refers to the 'echo.py' file
       "surround",  # refers to the 'surround.py' file
       "reverse",   # !!! refers to the 'reverse' function now !!!
   ]

   def reverse(msg: str):  # <-- this name shadows the 'reverse.py' submodule
       return msg[::-1]    #     in the case of a 'from sound.effects import *'

Se "__all__" non è definito, l'istruzione "from sound.effects import
*" *non* importa tutti i sottomoduli del pacchetto "sound.effects"
nello spazio dei nomi corrente; si limita ad assicurare che il
pacchetto "sound.effects" sia stato importato (eventualmente eseguendo
qualsiasi codice di inizializzazione in "__init__.py") e quindi
importa solo i nomi definiti nel pacchetto. Questo include qualsiasi
nome definito (e sottomoduli esplicitamente caricati) nel file
"__init__.py". Include anche eventuali sottomoduli del pacchetto che
sono stati esplicitamente caricati da precedenti istruzioni di
"import". Considera questo codice:

   import sound.effects.echo
   import sound.effects.surround
   from sound.effects import *

In questo esempio, i moduli "echo" e "surround" sono importati nello
spazio dei nomi corrente perché sono definiti nel pacchetto
"sound.effects" quando viene eseguita l'istruzione "from...import".
(Questo funziona anche quando è definito "__all__".)

Sebbene certi moduli siano progettati per esportare solo nomi che
seguono certi schemi quando usi "import *", è comunque considerata una
cattiva pratica nel codice di produzione.

Ricorda, non c'è nulla di sbagliato nell'usare "from package import
specific_submodule"! Infatti, questa è la notazione raccomandata a
meno che il modulo importante non debba usare sottomoduli con lo
stesso nome da pacchetti differenti.


6.4.2. Riferimenti Intra-pacchetto
----------------------------------

Quando i pacchetti sono strutturati in sottopacchetti (come il
pacchetto "sound" nell'esempio), puoi usare importazioni assolute per
riferirti a sottomoduli di pacchetti fratelli. Ad esempio, se il
modulo "sound.filters.vocoder" deve utilizzare il modulo "echo" nel
pacchetto "sound.effects", può usare "from sound.effects import echo".

Puoi anche scrivere importazioni relative, con la forma
dell'istruzione di importazione "from module import name". Queste
importazioni utilizzano punti di testa per indicare i pacchetti
corrente e genitore coinvolti nell'importazione relativa. Dal modulo
"surround", ad esempio, potresti usare:

   from . import echo
   from .. import formats
   from ..filters import equalizer

Note that relative imports are based on the name of the current
module's package. Since the main module does not have a package,
modules intended for use as the main module of a Python application
must always use absolute imports.


6.4.3. Pacchetti in Directory Multiple
--------------------------------------

Packages support one more special attribute, "__path__".  This is
initialized to be a *sequence* of strings containing the name of the
directory holding the package's "__init__.py" before the code in that
file is executed.  This variable can be modified; doing so affects
future searches for modules and subpackages contained in the package.

Sebbene questa funzione non sia spesso necessaria, può essere
utilizzata per estendere il set di moduli trovati in un pacchetto.

-[ Note ]-

[1] In realtà anche le definizioni di funzione sono 'istruzioni' che
    vengono 'eseguite'; l'esecuzione di una definizione di funzione a
    livello di modulo aggiunge il nome della funzione allo spazio dei
    nomi globale del modulo.
