19. Definire e chiamare le funzioni
19.1) Cosa sono le funzioni e perché sono importanti
Una funzione(function) è un blocco di codice con un nome che svolge un compito specifico. Hai già usato funzioni in tutto questo libro—print(), input(), len(), type() e molte altre. Queste sono funzioni integrate (built-in functions) fornite da Python. Ora imparerai a creare le tue funzioni personalizzate (custom functions) per organizzare il codice e renderlo riutilizzabile.
Perché le funzioni sono importanti
Le funzioni sono fondamentali per scrivere programmi chiari e manutenibili. Offrono diversi vantaggi critici:
1. Riutilizzo del codice
Senza funzioni, dovresti copiare e incollare lo stesso codice ogni volta che vuoi svolgere un’attività. Considera il calcolo dell’area di un rettangolo in più punti:
# Senza funzioni - codice ripetitivo
length1 = 5
width1 = 3
area1 = length1 * width1
print(f"Area 1: {area1}")
length2 = 8
width2 = 4
area2 = length2 * width2
print(f"Area 2: {area2}")
length3 = 10
width3 = 6
area3 = length3 * width3
print(f"Area 3: {area3}")Output:
Area 1: 15
Area 2: 32
Area 3: 60Questa ripetizione è noiosa e soggetta a errori. Se devi cambiare il modo in cui calcoli l’area (magari per includere unità di misura o arrotondamenti), dovresti aggiornare ogni punto. Le funzioni risolvono questo problema permettendoti di scrivere il codice una sola volta e usarlo molte volte.
2. Organizzazione del codice
Le funzioni suddividono programmi grandi in parti più piccole e gestibili. Ogni funzione gestisce un compito specifico, rendendo il codice più facile da capire e mantenere. Invece di uno script lungo con centinaia di righe, puoi organizzare operazioni correlate in funzioni con un nome che comunica chiaramente il loro scopo.
3. Astrazione
Le funzioni nascondono i dettagli di implementazione dietro un’interfaccia semplice. Quando chiami len(my_list), non devi sapere come Python conta gli elementi—ottieni semplicemente il risultato. Allo stesso modo, le tue funzioni possono fornire interfacce semplici per operazioni complesse, rendendo il tuo codice più facile da usare e comprendere.
4. Test e debugging
Le funzioni rendono più facile testare singole parti del programma. Puoi verificare che ogni funzione funzioni correttamente in isolamento prima di combinarla in un programma più grande. Quando qualcosa va storto, le funzioni ti aiutano a restringere dove si sta verificando il problema.
Nel resto di questo capitolo, imparerai come definire le tue funzioni, passare informazioni, ottenere risultati e documentarle in modo chiaro. Queste competenze sono essenziali per scrivere codice Python professionale.
19.2) Definire funzioni con def
Per creare una funzione in Python, usi la parola chiave def (abbreviazione di "define"). La struttura di base di una definizione di funzione appare così:
def function_name():
# Blocco di codice che viene eseguito quando la funzione viene chiamata
statement1
statement2
# ... altre istruzioniVediamo nel dettaglio ogni parte:
def: la parola chiave che dice a Python che stai definendo una funzionefunction_name: il nome che scegli per la tua funzione (segue le stesse regole dei nomi delle variabili)(): parentesi che alla fine conterranno i parametri (li vedremo nella prossima sezione):: i due punti che segnano la fine dell’intestazione della funzione- Blocco di codice indentato: le istruzioni che compongono il corpo della funzione (devono essere indentate)
La tua prima funzione
Ecco una funzione semplice che stampa un saluto:
def greet():
print("Hello!")
print("Welcome to Python functions.")
# Chiamata della funzione
greet()Output:
Hello!
Welcome to Python functions.Quando definisci una funzione, Python la memorizza ma non esegue subito il codice al suo interno. Il codice viene eseguito solo quando chiami (call) la funzione scrivendo il suo nome seguito da parentesi: greet().
Convenzioni di denominazione delle funzioni
I nomi delle funzioni seguono le stesse regole dei nomi delle variabili (come abbiamo imparato nel Capitolo 3):
- Usa lettere minuscole
- Separa le parole con underscore (snake_case)
- Inizia con una lettera o un underscore, non con una cifra
- Usa nomi descrittivi che indichino cosa fa la funzione
# Buoni nomi di funzioni
def calculate_total():
pass
def get_user_age():
pass
def display_menu():
pass
# Nomi di funzioni scadenti (ma sintatticamente validi)
def x(): # Non descrittivo
pass
def CalculateTotal(): # Dovrebbe usare lettere minuscole
pass
def calc(): # Troppo abbreviato
passNota: Usiamo pass qui come segnaposto (come abbiamo imparato nel Capitolo 8). Non fa nulla, ma permette che la definizione della funzione sia sintatticamente completa.
Le funzioni possono contenere qualsiasi codice
Il corpo di una funzione può contenere qualsiasi istruzione Python che hai imparato finora: assegnazioni di variabili, condizioni, cicli(loop), e persino chiamate ad altre funzioni.
def check_temperature():
temperature = 72
if temperature > 75:
print("It's warm.")
elif temperature > 60:
print("It's comfortable.")
else:
print("It's cool.")
check_temperature()Output:
It's comfortable.Definizioni multiple di funzioni
Puoi definire quante funzioni ti servono nel tuo programma. Ogni funzione è indipendente e può essere chiamata separatamente:
def morning_greeting():
print("Good morning!")
def evening_greeting():
print("Good evening!")
# Chiama ogni funzione
morning_greeting()
evening_greeting()Output:
Good morning!
Good evening!Ordine di definizione delle funzioni
In Python, devi definire una funzione prima di chiamarla. L’interprete Python legge il codice dall’alto verso il basso, quindi se provi a chiamare una funzione prima di definirla, otterrai un errore:
# WARNING: This will cause a NameError - for demonstration only
# PROBLEM: Function called before it's defined
say_hello() # NameError: name 'say_hello' is not defined
def say_hello():
print("Hello!")L’ordine corretto è definire prima, poi chiamare:
# Corretto: definisci prima
def say_hello():
print("Hello!")
# Poi chiama
say_hello()Output:
Hello!Tuttavia, le funzioni possono chiamare altre funzioni definite più avanti nel file, purché quelle chiamate avvengano dopo che tutte le definizioni sono state lette:
def first_function():
print("First function")
second_function() # Va bene - chiamata a runtime
def second_function():
print("Second function")
# Entrambe le funzioni sono definite prima che chiamiamo la prima
first_function()Output:
First function
Second functionLe funzioni creano uno scope locale
Le variabili create all’interno di una funzione esistono solo all’interno di quella funzione. Questo si chiama scope locale (local scope) (lo esploreremo nel dettaglio nel Capitolo 21). Per ora, capisci che ciò che accade dentro una funzione resta dentro la funzione:
def create_message():
message = "This is local"
print(message)
create_message()
# Questo causerebbe un errore:
# print(message) # NameError: name 'message' is not definedOutput:
This is localLa variabile message esiste solo mentre la funzione è in esecuzione. Una volta che la funzione termina, la variabile scompare.
Funzioni vuote con pass
A volte vuoi definire la struttura di una funzione ma implementarla più tardi. Usa pass come segnaposto:
def future_feature():
pass # TODO: Implementa questo più tardi
# La funzione esiste e può essere chiamata, ma non fa nulla
future_feature() # Esegue senza errori, non fa nullaQuesto è utile quando abbozzi la struttura del programma prima di riempire i dettagli.
19.3) Chiamare funzioni e passare argomenti
Definire una funzione crea un pezzo di codice riutilizzabile, ma per rendere le funzioni davvero potenti, devi passarvi informazioni. Queste informazioni vengono passate tramite argomenti (arguments).
Parametri vs argomenti
Prima di continuare, chiarifichiamo due termini che spesso vengono confusi:
- Parametro(parameter): un nome di variabile nella definizione della funzione che riceverà un valore
- Argomento(argument): il valore effettivo che passi alla funzione quando la chiami
def greet(name): # 'name' è un parametro
print(f"Hello, {name}!")
greet("Alice") # "Alice" è un argomentoOutput:
Hello, Alice!Pensa ai parametri come a segnaposto e agli argomenti come ai dati reali che riempiono quei segnaposto.
Definire funzioni con parametri
Per definire una funzione che accetta input, aggiungi i nomi dei parametri dentro le parentesi:
def greet_person(name):
print(f"Hello, {name}!")
print("Nice to meet you.")
# Chiama con argomenti diversi
greet_person("Alice")
print() # Riga vuota per leggibilità
greet_person("Bob")Output:
Hello, Alice!
Nice to meet you.
Hello, Bob!
Nice to meet you.Il parametro name agisce come una variabile dentro la funzione. Ogni volta che chiami la funzione, name assume il valore dell’argomento che fornisci.
Parametri multipli
Le funzioni possono accettare più parametri, separati da virgole:
def calculate_rectangle_area(length, width):
area = length * width
print(f"A rectangle with length {length} and width {width}")
print(f"has an area of {area} square units.")
calculate_rectangle_area(5, 3)
print()
calculate_rectangle_area(10, 7)Output:
A rectangle with length 5 and width 3
has an area of 15 square units.
A rectangle with length 10 and width 7
has an area of 70 square units.Quando chiami una funzione con più parametri, l’ordine conta. Il primo argomento va al primo parametro, il secondo argomento al secondo parametro, e così via. Questi sono chiamati argomenti posizionali (positional arguments).
Argomenti posizionali
Con gli argomenti posizionali, Python associa gli argomenti ai parametri in base alla loro posizione:
def describe_pet(animal_type, pet_name):
print(f"I have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name}.")
describe_pet("dog", "Buddy")
print()
describe_pet("cat", "Whiskers")Output:
I have a dog.
My dog's name is Buddy.
I have a cat.
My cat's name is Whiskers.Se confondi l’ordine, otterrai risultati inaspettati:
def describe_pet(animal_type, pet_name):
print(f"I have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name}.")
# Argomenti nell'ordine sbagliato
describe_pet("Buddy", "dog")Output:
I have a Buddy.
My Buddy's name is dog.Questo è Python tecnicamente valido, ma produce un output senza senso perché gli argomenti sono nelle posizioni sbagliate.
Argomenti per parola chiave
Per evitare errori legati alla posizione, puoi usare argomenti per parola chiave (keyword arguments) specificando esplicitamente i parametri quando chiami la funzione:
def describe_pet(animal_type, pet_name):
print(f"I have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name}.")
# Uso di argomenti per parola chiave - l'ordine non conta
describe_pet(animal_type="dog", pet_name="Buddy")
print()
describe_pet(pet_name="Whiskers", animal_type="cat")Output:
I have a dog.
My dog's name is Buddy.
I have a cat.
My cat's name is Whiskers.Con gli argomenti per parola chiave, l’ordine non conta perché Python associa gli argomenti ai parametri per nome, non per posizione.
Mescolare argomenti posizionali e per parola chiave
Puoi mescolare argomenti posizionali e per parola chiave in una singola chiamata di funzione, ma gli argomenti posizionali devono venire per primi:
def create_profile(username, email, age):
print(f"Username: {username}")
print(f"Email: {email}")
print(f"Age: {age}")
# Mescolare argomenti posizionali e per parola chiave
create_profile("alice123", email="alice@example.com", age=25)Output:
Username: alice123
Email: alice@example.com
Age: 25Tuttavia, non puoi mettere argomenti posizionali dopo argomenti per parola chiave:
# WARNING: This will cause a SyntaxError - for demonstration only
# PROBLEM: Positional argument after keyword argument
# create_profile(username="alice123", "alice@example.com", 25)
# SyntaxError: positional argument follows keyword argumentIl numero di argomenti deve corrispondere
Quando chiami una funzione, devi fornire il numero corretto di argomenti (a meno che la funzione non abbia valori predefiniti, che tratteremo nel Capitolo 20):
def add_numbers(a, b):
result = a + b
print(f"{a} + {b} = {result}")
add_numbers(5, 3) # Corretto: 2 argomenti per 2 parametriOutput:
5 + 3 = 8Fornire troppo pochi o troppi argomenti causa un errore:
# WARNING: These will cause TypeErrors - for demonstration only
# PROBLEM: Too few arguments
# add_numbers(5)
# TypeError: add_numbers() missing 1 required positional argument: 'b'
# PROBLEM: Too many arguments
# add_numbers(5, 3, 2)
# TypeError: add_numbers() takes 2 positional arguments but 3 were givenUsare espressioni come argomenti
Gli argomenti non devono essere valori semplici—puoi usare qualsiasi espressione:
def display_total(price, quantity):
total = price * quantity
print(f"Total cost: ${total:.2f}")
# Usare espressioni come argomenti
base_price = 10
display_total(base_price * 1.1, 5) # Prezzo con ricarico del 10%
display_total(15 + 5, 3 * 2) # Entrambi gli argomenti sono espressioniOutput:
Total cost: $55.00
Total cost: $120.00Python valuta prima ogni espressione, poi passa i valori risultanti alla funzione.
Chiamare funzioni dall’interno di funzioni
Le funzioni possono chiamare altre funzioni, creando una gerarchia di operazioni. Questa è una tecnica potente che ti permette di suddividere compiti complessi in parti più piccole e gestibili.
Ecco un esempio con il calcolo dell’area di una stanza:
def calculate_area(length, width):
return length * width
def display_room_info(room_name, length, width):
area = calculate_area(length, width)
print(f"Room: {room_name}")
print(f"Dimensions: {length} x {width}")
print(f"Area: {area} square feet")
display_room_info("Living Room", 15, 12)Output:
Room: Living Room
Dimensions: 15 x 12
Area: 180 square feetNota: Qui stiamo usando return, che esploreremo nel dettaglio nella prossima sezione. Per ora, capisci che calculate_area() rimanda il suo risultato alla funzione chiamante.
Ecco un altro esempio che mostra come le funzioni possano costruire l’una sull’altra—un sistema di conversione della temperatura:
def celsius_to_fahrenheit(celsius):
return (celsius * 9/5) + 32
def format_temperature(fahrenheit):
return f"{fahrenheit:.1f}°F"
def display_temperature_conversion(celsius):
fahrenheit = celsius_to_fahrenheit(celsius)
formatted = format_temperature(fahrenheit)
print(f"{celsius}°C equals {formatted}")
# Usa il sistema di conversione completo
display_temperature_conversion(25)
display_temperature_conversion(0)
display_temperature_conversion(100)Output:
25°C equals 77.0°F
0°C equals 32.0°F
100°C equals 212.0°FIn questo esempio, display_temperature_conversion() chiama celsius_to_fahrenheit() per fare la conversione, poi chiama format_temperature() per formattare il risultato. Ogni funzione ha una singola responsabilità chiara, rendendo il codice facile da capire e mantenere.
19.4) Usare return per rimandare risultati
Finora, le nostre funzioni hanno eseguito azioni (come stampare), ma non hanno rimandato valori al codice che le ha chiamate. L’istruzione return permette a una funzione di calcolare un risultato e rimandarlo al chiamante.
Istruzione return di base
Ecco una funzione semplice che calcola e restituisce un valore:
def add_numbers(a, b):
result = a + b
return result
# Cattura il valore restituito
sum_value = add_numbers(5, 3)
print(f"The sum is: {sum_value}")Output:
The sum is: 8Quando Python incontra un’istruzione return, accadono due cose:
- La funzione interrompe immediatamente l’esecuzione (qualsiasi codice dopo
returnviene ignorato) - Il valore specificato viene rimandato al chiamante
Restituire valori direttamente
Non devi salvare il risultato in una variabile prima di restituirlo. Puoi restituire direttamente un’espressione:
def multiply(a, b):
return a * b
result = multiply(4, 7)
print(f"4 × 7 = {result}")Output:
4 × 7 = 28Questo è più conciso ed è lo stile preferito per calcoli semplici.
Usare i valori restituiti
Una volta che una funzione restituisce un valore, puoi usare quel valore ovunque useresti qualsiasi altro valore:
def calculate_discount(price, discount_percent):
discount_amount = price * (discount_percent / 100)
return discount_amount
original_price = 100
discount = calculate_discount(original_price, 20)
# Usa il valore restituito nei calcoli
final_price = original_price - discount
print(f"Original price: ${original_price:.2f}")
print(f"Discount: ${discount:.2f}")
print(f"Final price: ${final_price:.2f}")Output:
Original price: $100.00
Discount: $20.00
Final price: $80.00return termina immediatamente la funzione
Quando Python esegue un’istruzione return, la funzione termina immediatamente. Qualsiasi codice dopo il return non viene mai eseguito:
def check_age(age):
if age < 18:
return "Minor"
# Questa riga viene eseguita solo se age >= 18
return "Adult"
print(check_age(15))
print(check_age(25))Output:
Minor
AdultQuesto comportamento è utile per gestire casi diversi in una funzione. Una volta determinato il risultato, puoi restituire subito senza dover controllare condizioni aggiuntive.
Ecco un esempio che mostra come return interrompa l’esecuzione:
def process_number(n):
if n < 0:
return "Negative"
print("This line runs for non-negative numbers")
if n == 0:
return "Zero"
print("This line runs for positive numbers")
return "Positive"
print(process_number(-5))
print()
print(process_number(0))
print()
print(process_number(10))Output:
Negative
This line runs for non-negative numbers
Zero
This line runs for non-negative numbers
This line runs for positive numbers
PositiveFunzioni senza return
Se una funzione non ha un’istruzione return, oppure se ha un return senza valore, la funzione restituisce None:
def greet(name):
print(f"Hello, {name}!")
# Nessuna istruzione return
result = greet("Alice")
print(f"The function returned: {result}")Output:
Hello, Alice!
The function returned: NoneAllo stesso modo, un return “nudo” (senza valore) restituisce None:
def process_data(data):
if not data:
return # Uscita anticipata, restituisce None
print(f"Processing: {data}")
return "Success"
result1 = process_data("")
result2 = process_data("some data")
print(f"Result 1: {result1}")
print(f"Result 2: {result2}")Output:
Processing: some data
Result 1: None
Result 2: SuccessRestituire più valori
Le funzioni Python possono restituire più valori separandoli con virgole. Python li impacchetta automaticamente in una tupla (come abbiamo imparato nel Capitolo 15):
def calculate_rectangle(length, width):
area = length * width
perimeter = 2 * (length + width)
return area, perimeter
# Decomponi la tupla restituita
rect_area, rect_perimeter = calculate_rectangle(5, 3)
print(f"Area: {rect_area}")
print(f"Perimeter: {rect_perimeter}")Output:
Area: 15
Perimeter: 16Puoi anche catturare la tupla come singolo valore:
def get_student_info():
name = "Alice"
age = 20
grade = "A"
return name, age, grade
# Cattura come tupla
student = get_student_info()
print(f"Student info: {student}")
print(f"Name: {student[0]}")Output:
Student info: ('Alice', 20, 'A')
Name: AliceRestituire tipi diversi
Una funzione può restituire tipi diversi di valori a seconda della situazione:
def divide(a, b):
if b == 0:
return "Error: Division by zero"
return a / b
result1 = divide(10, 2)
result2 = divide(10, 0)
print(f"10 / 2 = {result1}")
print(f"10 / 0 = {result2}")Output:
10 / 2 = 5.0
10 / 0 = Error: Division by zeroAnche se funziona, in generale è una pratica migliore gestire gli errori in modo diverso (impareremo le eccezioni nella Parte VII). Per ora, capisci che le funzioni possono restituire tipi diversi, anche se spesso è più chiaro essere coerenti.
19.5) Documentare le funzioni con le docstring
Man mano che i tuoi programmi crescono e crei più funzioni, diventa cruciale documentare cosa fa ciascuna funzione. Python fornisce un modo integrato per documentare le funzioni usando le docstring(docstrings) (stringhe di documentazione).
Che cos’è una docstring?
Una docstring(docstring) è un letterale stringa che appare come prima istruzione in una funzione (o modulo, classe o metodo). Descrive cosa fa la funzione, quali parametri accetta e cosa restituisce. Le docstring sono racchiuse tra triple virgolette (""" o '''), che consentono loro di estendersi su più righe.
def calculate_area(length, width):
"""Calculate the area of a rectangle.
Takes the length and width of a rectangle and returns the area.
"""
return length * widthPerché le docstring sono importanti
Le docstring servono a diversi scopi importanti:
- Auto-documentazione: spiegano cosa fa la funzione senza richiedere ai lettori di analizzare il codice
- Supporto IDE: molti strumenti di sviluppo mostrano le docstring come tooltip quando usi una funzione
- Funzione help(): la funzione integrata
help()di Python mostra le docstring - Pratica professionale: codice ben documentato è più facile da mantenere e condividere con altri
Formato base delle docstring
Per funzioni semplici, è sufficiente una docstring su una riga:
def greet(name):
"""Print a personalized greeting."""
print(f"Hello, {name}!")
# Accedi alla docstring
print(greet.__doc__)Output:
Print a personalized greeting.La docstring dovrebbe essere una descrizione concisa di ciò che fa la funzione, scritta come un comando ("Calculate...", "Return...", "Print...") piuttosto che una descrizione ("This function calculates...").
Docstring su più righe
Per funzioni più complesse, usa docstring su più righe che includano:
- Un breve riepilogo sulla prima riga
- Una riga vuota
- Una descrizione più dettagliata
- Informazioni sui parametri
- Informazioni sui valori restituiti
def calculate_discount(price, discount_percent):
"""Calculate the discounted price.
Takes an original price and a discount percentage, then returns
the amount of discount that should be applied.
Parameters:
price (float): The original price before discount
discount_percent (float): The discount percentage (0-100)
Returns:
float: The discount amount in the same currency as the price
"""
return price * (discount_percent / 100)
# Usa help() per vedere la docstring completa
help(calculate_discount)Output:
Help on function calculate_discount in module __main__:
calculate_discount(price, discount_percent)
Calculate the discounted price.
Takes an original price and a discount percentage, then returns
the amount of discount that should be applied.
Parameters:
price (float): The original price before discount
discount_percent (float): The discount percentage (0-100)
Returns:
float: The discount amount in the same currency as the priceConvenzioni delle docstring
Python ha convenzioni consolidate per scrivere docstring (documentate in PEP 257). Ecco le linee guida principali:
1. Usa triple virgolette doppie: """docstring"""
def good_example():
"""This follows the convention."""
pass
def also_valid():
'''This works but is less common.'''
pass2. Le docstring su una riga dovrebbero stare su una sola riga:
def add(a, b):
"""Return the sum of a and b."""
return a + b3. Le docstring su più righe dovrebbero avere una riga di riepilogo, poi una riga vuota:
def process_order(order_id, items):
"""Process a customer order and update inventory.
This function validates the order, checks inventory availability,
calculates the total cost, and updates the inventory database.
Parameters:
order_id (str): Unique identifier for the order
items (list): List of item dictionaries with 'product' and 'quantity'
Returns:
dict: Order summary with 'total', 'status', and 'confirmation_number'
"""
# Implementazione della funzione qui
passDescrivere parametri e valori restituiti
Quando documenti parametri e valori restituiti, sii specifico su:
- Nomi dei parametri: corrispondono ai nomi reali dei parametri nella funzione
- Tipi: che tipo di dato è atteso (impareremo i type hints nel Capitolo 43)
- Scopo: a cosa serve il parametro
- Valore restituito: cosa restituisce la funzione e in quali condizioni
def find_student(student_id, students):
"""Find a student by ID in a list of student records.
Parameters:
student_id (int): The unique ID number of the student to find
students (list): List of student dictionaries, each containing 'id' and 'name'
Returns:
dict: The student dictionary if found, None if not found
"""
for student in students:
if student['id'] == student_id:
return student
return NoneDocstring per funzioni con più tipi di ritorno
Quando una funzione può restituire tipi diversi a seconda della situazione, documenta tutte le possibilità:
def safe_divide(a, b):
"""Divide two numbers with error handling.
Parameters:
a (float): The dividend
b (float): The divisor
Returns:
float: The quotient if division is successful
str: An error message if b is zero
"""
if b == 0:
return "Error: Cannot divide by zero"
return a / bAccedere alle docstring
Puoi accedere alla docstring di una funzione in tre modi:
1. Usando l’attributo __doc__:
def example():
"""This is an example function."""
pass
print(example.__doc__)Output:
This is an example function.2. Usando la funzione help():
def calculate_bmi(weight, height):
"""Calculate Body Mass Index.
Parameters:
weight (float): Weight in kilograms
height (float): Height in meters
Returns:
float: BMI value
"""
return weight / (height ** 2)
help(calculate_bmi)Output:
Help on function calculate_bmi in module __main__:
calculate_bmi(weight, height)
Calculate Body Mass Index.
Parameters:
weight (float): Weight in kilograms
height (float): Height in meters
Returns:
float: BMI value3. In ambienti di sviluppo interattivi: la maggior parte degli IDE e degli editor di codice mostra le docstring come tooltip quando passi sopra o digiti il nome di una funzione.
Quando scrivere docstring
Dovresti scrivere docstring per:
- Tutte le funzioni pubbliche: funzioni pensate per essere usate da altre parti del programma o da altri programmatori
- Funzioni complesse: qualsiasi funzione il cui scopo o comportamento non sia immediatamente ovvio dal nome e dai parametri
- Funzioni con parametri non ovvi: quando i nomi dei parametri da soli non spiegano completamente quali valori siano attesi
Potresti saltare le docstring per:
- Funzioni molto semplici e ovvie: funzioni come
def add(a, b): return a + bin cui nome e parametri rendono lo scopo cristallino - Funzioni di supporto private: piccole funzioni interne usate solo all’interno di una funzione più grande (anche se anche queste beneficiano di docstring brevi)
Le docstring non sono commenti
Ricorda che le docstring servono a uno scopo diverso rispetto ai commenti:
- Docstring: descrivono cosa fa una funzione e come usarla (l’interfaccia)
- Commenti: spiegano come funziona internamente il codice (l’implementazione)
def calculate_grade(score, total):
"""Calculate the percentage grade from a score.
Parameters:
score (int): Points earned
total (int): Total points possible
Returns:
float: The percentage grade (0-100)
"""
# Evita la divisione per zero
if total == 0:
return 0.0
# Calcola la percentuale e arrotonda a 2 decimali
percentage = (score / total) * 100
return round(percentage, 2)La docstring dice agli utenti cosa fa la funzione e come usarla. I commenti spiegano dettagli specifici dell’implementazione a chi legge il codice.
Costruire buone abitudini di documentazione
Scrivere docstring chiare è un’abitudine che ripaga:
- Scrivi le docstring mentre scrivi le funzioni: non aspettare dopo—documenta mentre lo scopo della funzione è fresco nella tua mente
- Tieni aggiornate le docstring: quando cambi il comportamento di una funzione, aggiorna la sua docstring
- Sii conciso ma completo: includi tutte le informazioni necessarie, ma evita verbosità non necessaria
- Usa esempi quando è utile: per funzioni complesse, un esempio d’uso nella docstring può essere inestimabile
Una buona documentazione rende il tuo codice più professionale, più facile da mantenere e più prezioso per gli altri (incluso il te stesso del futuro).