Python & AI Tutorials Logo
Programmazione Python

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:

python
# 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: 60

Questa 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ì:

python
def function_name():
    # Blocco di codice che viene eseguito quando la funzione viene chiamata
    statement1
    statement2
    # ... altre istruzioni

Vediamo nel dettaglio ogni parte:

  • def: la parola chiave che dice a Python che stai definendo una funzione
  • function_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:

python
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
python
# 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
    pass

Nota: 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.

python
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:

python
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:

python
# 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:

python
# 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:

python
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 function

Le 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:

python
def create_message():
    message = "This is local"
    print(message)
 
create_message()
 
# Questo causerebbe un errore:
# print(message)  # NameError: name 'message' is not defined

Output:

This is local

La 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:

python
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 nulla

Questo è 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
python
def greet(name):  # 'name' è un parametro
    print(f"Hello, {name}!")
 
greet("Alice")  # "Alice" è un argomento

Output:

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:

python
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:

python
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:

python
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:

python
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:

python
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:

python
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: 25

Tuttavia, non puoi mettere argomenti posizionali dopo argomenti per parola chiave:

python
# 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 argument

Il 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):

python
def add_numbers(a, b):
    result = a + b
    print(f"{a} + {b} = {result}")
 
add_numbers(5, 3)  # Corretto: 2 argomenti per 2 parametri

Output:

5 + 3 = 8

Fornire troppo pochi o troppi argomenti causa un errore:

python
# 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 given

Usare espressioni come argomenti

Gli argomenti non devono essere valori semplici—puoi usare qualsiasi espressione:

python
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 espressioni

Output:

Total cost: $55.00
Total cost: $120.00

Python 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:

python
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 feet

Nota: 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:

python
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°F

In 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:

python
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: 8

Quando Python incontra un’istruzione return, accadono due cose:

  1. La funzione interrompe immediatamente l’esecuzione (qualsiasi codice dopo return viene ignorato)
  2. 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:

python
def multiply(a, b):
    return a * b
 
result = multiply(4, 7)
print(f"4 × 7 = {result}")

Output:

4 × 7 = 28

Questo è 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:

python
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.00

return termina immediatamente la funzione

Quando Python esegue un’istruzione return, la funzione termina immediatamente. Qualsiasi codice dopo il return non viene mai eseguito:

python
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
Adult

Questo 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:

python
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
Positive

Funzioni senza return

Se una funzione non ha un’istruzione return, oppure se ha un return senza valore, la funzione restituisce None:

python
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: None

Allo stesso modo, un return “nudo” (senza valore) restituisce None:

python
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: Success

Restituire 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):

python
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: 16

Puoi anche catturare la tupla come singolo valore:

python
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: Alice

Restituire tipi diversi

Una funzione può restituire tipi diversi di valori a seconda della situazione:

python
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 zero

Anche 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.

python
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 * width

Perché le docstring sono importanti

Le docstring servono a diversi scopi importanti:

  1. Auto-documentazione: spiegano cosa fa la funzione senza richiedere ai lettori di analizzare il codice
  2. Supporto IDE: molti strumenti di sviluppo mostrano le docstring come tooltip quando usi una funzione
  3. Funzione help(): la funzione integrata help() di Python mostra le docstring
  4. 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:

python
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
python
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 price

Convenzioni delle docstring

Python ha convenzioni consolidate per scrivere docstring (documentate in PEP 257). Ecco le linee guida principali:

1. Usa triple virgolette doppie: """docstring"""

python
def good_example():
    """This follows the convention."""
    pass
 
def also_valid():
    '''This works but is less common.'''
    pass

2. Le docstring su una riga dovrebbero stare su una sola riga:

python
def add(a, b):
    """Return the sum of a and b."""
    return a + b

3. Le docstring su più righe dovrebbero avere una riga di riepilogo, poi una riga vuota:

python
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
    pass

Descrivere 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
python
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 None

Docstring per funzioni con più tipi di ritorno

Quando una funzione può restituire tipi diversi a seconda della situazione, documenta tutte le possibilità:

python
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 / b

Accedere alle docstring

Puoi accedere alla docstring di una funzione in tre modi:

1. Usando l’attributo __doc__:

python
def example():
    """This is an example function."""
    pass
 
print(example.__doc__)

Output:

This is an example function.

2. Usando la funzione help():

python
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 value

3. 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 + b in 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)
python
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).

© 2025. Primesoft Co., Ltd.
support@primesoft.ai