I moduli (e i pacchetti) sono un ottimo modo Pythonic per dividere il tuo programma in spazi dei nomi separati, che sembra essere un obiettivo implicito di questa domanda. In effetti, mentre stavo imparando le basi di Python, mi sono sentito frustrato dalla mancanza di una funzionalità di ambito di blocco. Tuttavia, una volta compresi i moduli Python, ho potuto realizzare in modo più elegante i miei obiettivi precedenti senza la necessità di un ambito di blocco.
Come motivazione e per indirizzare le persone verso la giusta direzione, penso che sia utile fornire esempi espliciti di alcuni costrutti di scoping di Python. Per prima cosa spiego il mio tentativo fallito di utilizzare le classi Python per implementare l'ambito del blocco. Successivamente spiego come ho ottenuto qualcosa di più utile utilizzando i moduli Python. Alla fine delineo una pratica applicazione dei pacchetti al caricamento e al filtraggio dei dati.
Tentativo di ambito di blocco con le classi
Per alcuni istanti ho pensato di aver raggiunto l'ambito del blocco inserendo il codice all'interno di una dichiarazione di classe:
x = 5
class BlockScopeAttempt:
x = 10
print(x)
print(x)
Purtroppo questo si interrompe quando viene definita una funzione:
x = 5
class BlockScopeAttempt:
x = 10
print(x)
def printx2():
print(x)
printx2()
Questo perché le funzioni definite all'interno di una classe utilizzano l'ambito globale. Il modo più semplice (sebbene non l'unico) per risolvere questo problema è specificare esplicitamente la classe:
x = 5
class BlockScopeAttempt:
x = 10
print(x)
def printx2():
print(BlockScopeAttempt.x)
printx2()
Non è così elegante perché si devono scrivere funzioni in modo diverso a seconda che siano contenute o meno in una classe.
Risultati migliori con i moduli Python
I moduli sono molto simili alle classi statiche, ma secondo la mia esperienza i moduli sono molto più puliti. Per fare lo stesso con i moduli, creo un file chiamato my_module.pynella directory di lavoro corrente con i seguenti contenuti:
x = 10
print(x)
def printx():
global x
print(x)
Quindi nel mio file principale o nella sessione interattiva (ad esempio Jupyter), lo faccio
x = 5
import my_module
my_module.printx()
print(x)
Come spiegazione, ogni file Python definisce un modulo che ha il proprio spazio dei nomi globale. L'importazione di un modulo consente di accedere alle variabili in questo spazio dei nomi con la .sintassi.
Se stai lavorando con i moduli in una sessione interattiva, puoi eseguire queste due righe all'inizio
%load_ext autoreload
%autoreload 2
ei moduli verranno ricaricati automaticamente quando i file corrispondenti vengono modificati.
Pacchetti per il caricamento e il filtraggio dei dati
L'idea dei pacchetti è una leggera estensione del concetto di moduli. Un pacchetto è una directory contenente un file (possibilmente vuoto) __init__.py, che viene eseguito durante l'importazione. È possibile accedere ai moduli / pacchetti all'interno di questa directory con la .sintassi.
Per l'analisi dei dati, spesso ho bisogno di leggere un file di dati di grandi dimensioni e quindi applicare in modo interattivo vari filtri. La lettura di un file richiede diversi minuti, quindi voglio farlo solo una volta. Sulla base di ciò che ho imparato a scuola sulla programmazione orientata agli oggetti, credevo che si dovesse scrivere il codice per il filtraggio e il caricamento come metodi in una classe. Uno dei principali svantaggi di questo approccio è che se poi ridefinisco i miei filtri, la definizione della mia classe cambia, quindi devo ricaricare l'intera classe, inclusi i dati.
Oggigiorno con Python definisco un pacchetto chiamato my_datache contiene sottomoduli denominati loade filter. All'interno di filter.pyposso fare un'importazione relativa:
from .load import raw_data
Se modifico filter.py, autoreloadrileverà le modifiche. Non si ricarica load.py, quindi non ho bisogno di ricaricare i miei dati. In questo modo posso prototipare il mio codice di filtraggio in un notebook Jupyter, avvolgerlo come funzione e quindi tagliare e incollare dal mio notebook direttamente in filter.py. Capirlo ha rivoluzionato il mio flusso di lavoro e mi ha convertito da scettico a credente nello "Zen di Python".
One purpose (of many) is to improve code readability- Il codice Python, scritto correttamente (cioè seguendo lo zen di python ) non avrebbe bisogno di tali guarnizioni per essere leggibile. In effetti, è una delle (molte) cose che mi piacciono di Python.