Corso
PEP-8, ovvero Python Enhancement Proposal, presenta alcuni punti chiave che puoi usare per rendere il tuo codice più organizzato e leggibile. Come dice il creatore di Python, Guido Van Rossum:
Il codice viene letto molto più spesso di quanto non venga scritto.
In questo post, inizierai a esplorare PEP-8 con alcuni esempi di codice! Tratterai i seguenti argomenti:
- Per prima cosa, un'introduzione a PEP-8: cos'è e perché ti serve;
- Poi affronterai l'indentazione, un tema caldo tra i programmatori. Dovresti usare tab o spazi? In questa sezione scoprirai la risposta;
- Magari non te lo aspetti, ma esistono linee guida sulla lunghezza massima delle righe;
- C'è anche un modo consigliato per gestire le righe vuote;
- Inoltre, gli spazi bianchi in espressioni e istruzioni sono qualcosa che puoi gestire facilmente anche da principiante;
- Che cos'è l'encoding e perché potresti averne bisogno lavorando con Python? Qual è l'encoding predefinito in Python 3? La sezione sull'encoding dei file sorgente affronterà tutto questo.
- Probabilmente fai spesso import quando scrivi codice. Questa sezione tratterà argomenti come l'ordine degli import, import assoluti e relativi, import con wildcard, ecc.;
- La documentazione è essenziale per tenere traccia di tutti gli aspetti di un'applicazione e migliora la qualità complessiva del prodotto finale. I commenti qui sono fondamentali!
- Conosci i dunder name a livello di modulo? Sono particolarmente utili nelle docstring!
- Infine, imparerai di più sulle convenzioni di denominazione: scoprirai come scegliere i nomi delle funzioni, quali stili usare di solito e molto altro;
- Il tuo codice è conforme a PEP-8? È decisamente una domanda da farti. Per questo l'ultima sezione copre alcuni strumenti che ti aiutano a verificare se il tuo codice rispetta le linee guida presentate in questo post e le molte altre che non sono state trattate qui!
Introduzione a PEP-8
Il linguaggio di programmazione Python è diventato uno dei preferiti da molti. È un linguaggio relativamente facile da imparare, multiparadigma, con moltissimi moduli open source che ne ampliano l'utilità, ed è uno strumento di riferimento nella comunità della data science e dello sviluppo web.
Tuttavia, puoi sfruttare i vantaggi di Python solo quando sai esprimere meglio le tue idee con il codice. Python è stato creato con alcuni obiettivi in mente, che puoi vedere digitando import this.
import this
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
Qui sopra ci sono i 20 principi su cui si basa la programmazione in Python, noti come Zen di Python. Noterai anche "Readability Counts" nell'output, che dovrebbe essere la tua principale preoccupazione quando scrivi codice: altri programmatori o data scientist dovrebbero capire e poter contribuire al tuo codice affinché risolva il compito a portata di mano.
Le sezioni seguenti ti daranno ulteriori spunti su come riuscirci!
Indentazione
Quando programmi in Python, l'indentazione è qualcosa che userai sicuramente. Tuttavia, usala con attenzione, perché può causare errori di sintassi. La raccomandazione è quindi di usare quattro spazi per l'indentazione. Ad esempio, questa istruzione usa quattro spazi di indentazione:
if True:
print("If works")
Anche questo ciclo for con l'istruzione print è indentato con quattro spazi:
for element in range(0, 5):
print(element)
Quando scrivi un'espressione lunga, è meglio mantenerla allineata verticalmente. Così facendo, creerai un "hanging indent".
Ecco alcuni esempi di hanging indent in espressioni lunghe, che mostrano alcune varianti di utilizzo:
-
value = square_of_numbers(num1, num2, num3, num4) -
def square_of_number( num1, num2, num3, num4): return num1**2, num2**2, num3**2, num4**2 -
value = square_of_numbers( num1, num2, num3, num4) -
list_of_people = [ "Rama", "John", "Shiva" ] -
dict_of_people_ages = { "ram": 25, "john": 29, "shiva": 26 }
Ogni sviluppatore che lavora con Python o un altro linguaggio si chiede prima o poi se usare tab o spazi per l'indentazione. La differenza tra tab e spazi è un dibattito continuo nella comunità. Dai un'occhiata, per esempio, a questo articolo su Stackoverflow.
In generale, gli spazi sono il mezzo di indentazione preferito, ma se trovi script Python che usano già i tab, dovresti continuare con i tab. Altrimenti, dovresti sostituire l'indentazione di tutte le espressioni nello script con spazi.
Nota che Python 3 non consente di mescolare tab e spazi per l'indentazione. Per questo dovresti scegliere uno dei due e mantenerlo!
Lunghezza massima delle righe
In generale, è bene puntare a una lunghezza di 79 caratteri per riga nel codice Python.
Seguire questo numero obiettivo ha molti vantaggi. Eccone un paio:
- È possibile aprire i file affiancati per confrontarli;
- Puoi vedere l'intera espressione senza scorrere orizzontalmente, il che migliora leggibilità e comprensione del codice.
I commenti dovrebbero avere una lunghezza di riga di 72 caratteri. Più avanti in questo tutorial imparerai di più sulle convenzioni più comuni per i commenti!
Alla fine, sta a te quali convenzioni e stili di codifica seguire se lavori in un piccolo gruppo, ed è accettabile per la maggior parte degli sviluppatori deviare dalla linea guida sulla lunghezza massima. Tuttavia, se stai realizzando o contribuendo a un progetto open source, probabilmente vorrai e/o dovrai rispettare la regola sulla lunghezza massima delle righe stabilita da PEP-8.
Quando usi l'operatore +, è meglio inserire un corretto a capo, che rende il codice più facile da capire:
| Dovresti usare... | Dovresti evitare... |
|---|---|
|
|
|
In alternativa, potresti anche scrivere:
total = A
+ B
+ C
In breve, puoi andare a capo prima o dopo un operatore binario, purché tu sia coerente. Se stai scrivendo nuovo codice, prova a seguire l'ultima opzione presentata, dove vai a capo prima dell'operatore binario.
Righe vuote
Negli script Python, le funzioni e le classi di primo livello sono separate da due righe vuote. Le definizioni dei metodi all'interno delle classi dovrebbero essere separate da una riga vuota. Lo vedi chiaramente nel seguente esempio:
import unittest
class SwapTestSuite(unittest.TestCase):
"""
Swap Operation Test Case
"""
def setUp(self):
self.a = 1
self.b = 2
def test_swap_operations(self):
instance = Swap(self.a,self.b)
value1, value2 =instance.get_swap_values()
self.assertEqual(self.a, value2)
self.assertEqual(self.b, value1)
class OddOrEvenTestSuite(unittest.TestCase):
"""
This is the Odd or Even Test case Suite
"""
def setUp(self):
self.value1 = 1
self.value2 = 2
def test_odd_even_operations(self):
instance1 = OddOrEven(self.value1)
instance2 = OddOrEven(self.value2)
message1 = instance1.get_odd_or_even()
message2 = instance2.get_odd_or_even()
self.assertEqual(message1, 'Odd')
self.assertEqual(message2, 'Even')
Le classi SwapTestSuite e OddOrEvenTestSuite sono separate da due righe vuote, mentre le definizioni dei metodi, come .setUp() e .test_swap_operations(), hanno una sola riga vuota a separarle. Il codice verrà eseguito correttamente, ma non genererà output perché manca il codice necessario per avviare il test unitario (si tratta solo di mostrare le buone pratiche).
Spazi bianchi in espressioni e istruzioni
Dovresti cercare di evitare gli spazi bianchi superflui quando il tuo codice appare come nei seguenti esempi:
| Dovresti usare... | Dovresti evitare... |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
oppure
oppure
|
|
|
|
|
|
|
Questi esempi sono tratti da PEP-8.
Encoding dei file sorgente
Un computer non può memorizzare "lettere", "numeri", "immagini" o altro; può solo memorizzare e lavorare con bit, che possono avere solo valori binari: yes o no, true o false, 1 o 0, ecc. Come già sai, un computer funziona con l'elettricità; questo significa che un bit "reale" è la presenza o l'assenza di un impulso di elettricità. Di solito rappresenti questa presenza (o assenza) con 1 e 0.
Per usare i bit per rappresentare qualunque cosa oltre ai bit stessi, serve un insieme di regole. Devi convertire una sequenza di bit in qualcosa come lettere, numeri e immagini usando uno schema di codifica o encoding. Esempi di schemi di codifica sono ASCII, UTF-8, ecc.:
- L'American Standard Code for Information Interchange (ASCII) è il formato più comune per i file di testo nei computer e su Internet. In questo tipo di file, ogni carattere alfabetico, numerico o speciale è rappresentato con un numero binario a 7 bit (una stringa di sette 0 o 1).
- Unicode Worldwide Character Standard, o semplicemente Unicode, è un sistema per "l'interscambio, l'elaborazione e la visualizzazione dei testi scritti delle diverse lingue del mondo moderno". In breve, Unicode è progettato per includere tutti i sistemi di scrittura conosciuti al mondo. Attualmente Unicode impiega tre diverse codifiche per rappresentare i set di caratteri Unicode: UTF-8, UTF-16 e UTF-32.
- UTF-16 è una codifica Unicode a lunghezza variabile: i code point sono codificati con una o due unità di codice a 16 bit.
- UTF-8 è un altro tipo di codifica Unicode a lunghezza variabile, che usa da uno a quattro byte a 8 bit.
- UTF-32 è una codifica a lunghezza fissa che usa esattamente 32 bit per ogni code point Unicode.
Suggerimento: se vuoi saperne di più sull'encoding, dai un'occhiata a questo post.
Ora, perché è importante?
Avrai notato che le stringhe sono tra i tipi di dati più usati in Python. Come puoi aspettarti, arriverà il momento in cui vorrai lavorare con stringhe che contengono o sono composte interamente da caratteri che non fanno parte del set ASCII standard. Dopotutto, potresti dover lavorare con testi che contengono caratteri accentati, come á, ž, ç ecc.
In Python 3, UTF-8 è l'encoding sorgente predefinito. Ma, per chi usa Python 2, probabilmente già sai che lì il predefinito è ASCII.
Ma cosa succede se hai una stringa che contiene un carattere non ASCII, come "Flügel"?
Quando fai riferimento alla stringa in Python 2, otterrai quanto segue:
>>> s
'Fl\xfcgel'
Non sembra la tua stringa! Che succede quando la stampi?
>>> print(s)
Flügel
La stampa ti ha dato il valore assegnato alla variabile. Il carattere non ASCII ÃŒ è stato codificato. Ecco perché, quando hai fatto riferimento alla stringa, hai ottenuto \xfc. Per gestire questo, puoi usare i metodi di stringa .encode() e .decode(). Il primo restituisce una versione a 8 bit della stringa Unicode, codificata con l'encoding richiesto, mentre il secondo interpreta la stringa usando l'encoding fornito.
Import
Importare librerie e/o moduli è qualcosa che farai spesso quando lavori con Python per la data science. Come forse già sai, dovresti sempre importare le librerie all'inizio dello script.
Nota che, se fai molti import, dovresti assicurarti di dichiarare ogni import su una singola riga.
Dai un'occhiata alla seguente tabella per capirlo meglio:
| Dovresti usare... | Dovresti evitare... |
|---|---|
|
oppure
|
|
Inoltre, tieni conto che esiste un ordine da rispettare quando importi librerie. In generale, puoi seguire quest'ordine:
- Import della libreria standard.
- Import di terze parti correlati.
- Import specifici dell'applicazione/libreria locale.
Import assoluti e relativi
Inoltre, è bene conoscere la differenza tra import assoluti e relativi. In generale, in Python sono preferiti gli import assoluti, perché migliorano la leggibilità. Tuttavia, man mano che l'applicazione diventa più complessa, puoi usare anche gli import relativi. Gli import relativi impliciti non dovrebbero mai essere usati e sono stati rimossi in Python 3.
Ma cosa sono questi import assoluti e relativi?
-
Un import assoluto usa il percorso assoluto della funzione o classe, separato da
.. Per esempio,import sklearn.linear_model.LogisticRegression -
Un import relativo è relativo alla posizione corrente in cui si trova il tuo file Python. Potresti usare questo tipo di import se la struttura del tuo progetto cresce, perché renderà il progetto più leggibile. Ciò significa che, se hai una struttura di progetto Python come la seguente:
. ├── __init__.py ├── __init__.pyc ├── __pycache__ │ ├── __init__.cpython-35.pyc │ ├── bubble_sort.cpython-35.pyc │ ├── selection_sort.cpython-35.pyc ├── bubble_sort.py ├── heap_sort.py ├── insertion_sort.py ├── insertion_sort.pyc ├── merge_sort.py ├── merge_sort.pyc ├── quick_sort.py ├── radix_sort.py ├── selection_sort.py ├── selection_sort.pyc ├── shell_sort.py ├── tests │ ├── test1.py
Potresti usare un import relativo per importare l'algoritmo di bubble sort BubbleSort, memorizzato in bubble_sort.py in test1. Sarebbe così:
from ..bubble_sort import BubbleSort
Se vuoi saperne di più su import assoluti e relativi, puoi consultare PEP 328.
Import con wildcard
Infine, cerca di evitare gli import con wildcard, perché non migliorano la leggibilità; non hai visibilità su quali classi, metodi o variabili stai usando dal tuo modulo, per esempio:
from scikit import *
Commenti
I commenti vengono usati per la documentazione in-code in Python. Aggiungono comprensione al codice. Esistono molti strumenti per generare documentazione, come commenti e docstring, per il tuo modulo. I commenti dovrebbero essere più esplicativi, in modo che chi legge il codice possa comprenderlo correttamente e capire come viene usato insieme ad altre parti del codice.
I commenti iniziano con il simbolo #. Qualsiasi cosa scritta dopo l'hashtag non viene eseguita dall'interprete. Ad esempio, il seguente blocco di codice restituirà solo "This is a Python comment".
# This is a Python single line comment
print("This is a Python comment")
Ricorda: nella sezione precedente hai letto che i commenti dovrebbero avere una lunghezza di riga di 72 caratteri!
Detto questo, esistono tre tipi di commenti:
- Usi i commenti a blocchi per spiegare codice più complesso o poco familiare agli altri. Sono in genere commenti più lunghi e si applicano a parte o a tutto il codice che segue. I commenti a blocchi sono indentati allo stesso livello del codice. Ogni riga di un commento a blocchi inizia con l'hashtag
#e uno spazio. Se ti servono più paragrafi, dovrebbero essere separati da una riga che contiene solo#.
Guarda il seguente estratto, tratto dalla libreria scikit-learn, per capire come appaiono questi commenti:
if Gram is None or Gram is False:
Gram = None
if copy_X:
# force copy. setting the array to be fortran-ordered
# speeds up the calculation of the (partial) Gram matrix
# and allows to easily swap columns
X = X.copy('F')
- Dovresti usare con parsimonia i commenti in linea, anche se possono essere efficaci quando devi spiegare alcune parti del codice. Possono anche aiutarti a ricordare cosa significa una specifica riga o tornare utili quando collabori con qualcuno che non conosce tutti gli aspetti del tuo codice. Usi i commenti in linea sulla stessa riga dell'istruzione, dopo il codice stesso. Anche questi commenti iniziano con
#e uno spazio.
Per esempio:
counter = 0 # initialize the counter
- Scrivi le stringhe di documentazione o docstring all'inizio di moduli, file, classi e metodi pubblici. Questo tipo di commenti inizia con
"""e termina con""":
"""
This module is intended to provide functions for scientific computing
"""
Dunder name a livello di modulo
Ora che hai letto cosa sono le docstring, dovresti anche conoscere i dunder a livello di modulo, ovvero i nomi con due underscore iniziali e finali, che sono molto efficaci in Python. Sono i nomi speciali che Python definisce per non andare in conflitto con funzioni o nomi definiti dall'utente. Per maggiori informazioni, dai un'occhiata a questo articolo.
Un dunder a livello di modulo come (__all__, __author__, __version__) dovrebbe essere posizionato nella docstring principale del modulo e dovrebbe venire prima di tutti gli import. Dovresti definire gli import from __future__ prima di qualsiasi altro codice, tranne le docstring:
"""
Algos module consists of all the basic algorithms and their implementation
"""
from __future__ import print
__all__ = ['searching', 'sorting']
__version__ = '0.0.1'
__author__ = 'Chitrank Dixit'
import os
import sys
Suggerimento: consulta le seguenti convenzioni per scrivere docstring.
Convenzioni di denominazione
Quando programmi in Python, molto probabilmente userai una convenzione di denominazione, un insieme di regole per scegliere la sequenza di caratteri da usare per identificatori che denotano variabili, tipi, funzioni e altre entità nel codice sorgente e nella documentazione.
Se non sei sicuro di quali stili di denominazione esistano, considera i seguenti:
bo una singola lettera minuscola;Bo una singola lettera maiuscola;lowercaseUPPERCASElower_case_with_underscoresUPPER_CASE_WITH_UNDERSCORESCapitalizedWords, noto anche comeCapWords,CamelCaseoStudlyCaps.mixedCaseCapitalized_Words_With_Underscores_single_leading_underscore: debole indicatore di "uso interno". per esempio,from M import *non importa oggetti il cui nome inizia con underscore.single_trailing_underscore_: usato per convenzione per evitare conflitti con una keyword di Python, per esempio,Tkinter.Toplevel(master, class_='ClassName')__double_leading_underscore: quando si denomina un attributo di classe, attiva il name mangling (all'interno della classeFooBar,__boodiventa_FooBar__boo).__double_leading_and_trailing_underscore__: oggetti o attributi "magici" che vivono in namespace controllati dall'utente. Per esempio,__init__,__import__o__file__. Non dovresti mai inventare tali nomi, ma usarli solo come documentato.
Convenzioni generali di denominazione
La tabella seguente mostra alcune linee guida generali su come denominare i tuoi identificatori:
| Identificatore | Convenzione |
|---|---|
| Modulo | lowercase |
| Classe | CapWords |
| Funzioni | lowercase |
| Metodi | lowercase |
| Variabili di tipo | CapWords |
| Costanti | UPPERCASE |
| Package | lowercase |
- Non usare 'l', 'O' o 'I' come nome di variabile singolo: in alcuni font questi caratteri somigliano a zero (
0) e (1). - In generale, è bene usare nomi brevi quando possibile. In alcuni casi, puoi usare underscore per migliorare la leggibilità.
Se vuoi saperne di più sulle eccezioni alle convenzioni generali di denominazione, consulta questo articolo.
Il tuo codice è conforme a PEP-8?
Dopo aver imparato di più su PEP-8, probabilmente ti starai chiedendo come verificare se il tuo codice rispetta effettivamente queste linee guida (e altre non trattate in questo tutorial!).
Oltre a consultare direttamente PEP-8 e ad approfondirlo, dovresti sicuramente considerare l'utile modulo pep8, il pacchetto coala e alcune delle altre alternative descritte nelle prossime sezioni!
Pacchetto Python pep8
Il pacchetto pep8 può essere usato per controllare le incompatibilità con PEP-8 nel tuo codice Python e suggerire modifiche per adeguarlo alle linee guida. Puoi installare il modulo pep8 con pip eseguendo il seguente comando:
pip install pep8
Per dimostrare come funziona pep8, crea un nuovo file Python chiamato example.py con il seguente codice:
def my_function(a, b):
print("The sum of a and b is: ", a + b)
a = 1
b = 2
my_function(a,b)
Salva il file ed esegui poi il comando pep8 su di esso nel tuo terminale o prompt dei comandi come segue:
pep8 example.py
Questo stamperà eventuali incompatibilità con PEP-8 rilevate da pep8 nel codice, ad esempio:
example.py:1:1: E302 expected 2 blank lines, found 0
example.py:3:5: E225 missing whitespace around operator
example.py:5:5: E225 missing whitespace around operator
La prima riga dell'output indica che dovrebbero esserci due righe vuote prima della definizione della funzione alla riga 1. Le due righe successive indicano che dovrebbe esserci uno spazio attorno all'operatore di addizione nell'istruzione print e nelle istruzioni di assegnazione.
Per correggere questi problemi, puoi modificare il codice come segue:
def my_function(a, b):
print("The sum of a and b is:", a + b)
a = 1
b = 2
my_function(a, b)
Ora, quando esegui di nuovo pep8 example.py, non dovrebbe esserci alcun output, a indicare che il codice è ora conforme a PEP-8.
Puoi anche visualizzare il codice sorgente in cui viene trovata l'incompatibilità con l'argomento --show-source:
$ pep8 --show-source --show-pep8 testsuite/E40.py
testsuite/E40.py:2:10: E401 multiple imports on one line
import os, sys
^
Imports should usually be on separate lines.
Okay: import os\nimport sys
E401: import sys, os
Oppure puoi mostrare quanto spesso è stato trovato ciascun errore aggiungendo --statistics:
$ pep8 --statistics -qq Python-2.5/Lib
232 E201 whitespace after '['
599 E202 whitespace before ')'
631 E203 whitespace before ','
842 E211 whitespace before '('
2531 E221 multiple spaces before operator
4473 E301 expected 1 blank line, found 0
4006 E302 expected 2 blank lines, found 1
165 E303 too many blank lines (4)
325 E401 multiple imports on one line
3615 E501 line too long (82 characters)
612 W601 .has_key() is deprecated, use 'in'
1188 W602 deprecated form of raising exception
Suggerimento: assicurati anche di dare un'occhiata ad altri moduli, come flake8, autopep8 o pylint!
Analizzare il tuo codice con coala
coala fornisce linting e fixing per tutti i linguaggi, ma qui ti interessa soprattutto la programmazione in Python; puoi installare coala usando pip:
$ pip3 install coala-bears
Nel blocco di codice sopra, vedi che in realtà installi coala-bears: i bears sono plugin o moduli semplici che estendono le capacità di coala e variano da linguaggio a linguaggio. In questo caso, vuoi usare pep8bear, che trova il codice non conforme a PEP-8 e lo corregge in loco. Dovresti assolutamente considerare di usarlo per controllare il tuo codice Python.
$ coala -S python.bears=PEP8Bear python.files=\*\*/\*.py \
python.default_actions=PEP8Bear:ApplyPatchAction --save
# other output ...
Executing section python...
[INFO][11:03:37] Applied 'ApplyPatchAction' for 'PEP8Bear'.
[INFO][11:03:37] Applied 'ApplyPatchAction' for 'PEP8Bear'.
pep8online: verifica il tuo codice Python online
Oltre all'utile modulo pep8 e al pacchetto coala, puoi anche verificare se il tuo codice Python è conforme a PEP-8 andando su pep8online. Il sito ha un editor online che ti permette di incollare il tuo codice e premere il pulsante "Check code"! Come risultato, otterrai un feedback su cosa migliorare. Comodo e pratico!
Conclusione
Usando Python, a volte non ti preoccupi della qualità del codice per l'ansia di rilasciare funzionalità più velocemente. Tuttavia, le pratiche descritte in questo tutorial -e le molte altre non trattate qui- dovrebbero far parte del tuo ciclo develop-staging-test-deploy. Questo avvantaggia chiunque lavori al progetto: capire e, nella maggior parte dei casi, apportare modifiche al codice si può fare senza scavare a fondo e capire il codice avviando debugger. Se lavori su un progetto open source, i tuoi contributor troveranno PEP-8 una benedizione e capiranno meglio il tuo codice, dato che è lo standard universale seguito da ogni sviluppatore Python.
Ora che hai terminato questo tutorial, è un'ottima idea dare un'occhiata tu stesso a PEP-8! C'è molto altro da scoprire.
Se hai altri suggerimenti su come rispettare PEP-8 o pensi che ci sia sfuggito qualcosa di importante in questo articolo, non esitare a farcelo sapere su @DataCamp.

