Validation des arguments de fonction
Lors de la création de fonctions en Python, il est important de vérifier que les arguments passés à vos fonctions sont valides avant de procéder à la logique principale de la fonction. Dans cette étape, nous allons apprendre plusieurs techniques pour valider les arguments de fonction.
Création d'un nouveau fichier Python
Créons un nouveau fichier pour travailler avec les concepts de validation :
- Cliquez sur le menu "File" dans le WebIDE
- Sélectionnez "New File"
- Entrez
validate_args.py
comme nom de fichier
- Cliquez sur "OK"
Validation de base avec des conditionnelles
La façon la plus simple de valider les arguments est d'utiliser des instructions conditionnelles. Commençons par quelques validations de base :
def calculate_rectangle_area(length, width):
"""Calculate the area of a rectangle, validating inputs."""
## Validate that inputs are numbers
if not isinstance(length, (int, float)):
raise TypeError("Length must be a number")
if not isinstance(width, (int, float)):
raise TypeError("Width must be a number")
## Validate that inputs are positive
if length <= 0:
raise ValueError("Length must be positive")
if width <= 0:
raise ValueError("Width must be positive")
## Calculate the area
return length * width
## Test with valid inputs
try:
area = calculate_rectangle_area(5, 3)
print(f"Area of rectangle: {area}")
except (TypeError, ValueError) as e:
print(f"Error: {e}")
## Test with invalid types
try:
area = calculate_rectangle_area("5", 3)
print(f"Area of rectangle: {area}")
except (TypeError, ValueError) as e:
print(f"Error: {e}")
## Test with invalid values
try:
area = calculate_rectangle_area(5, -3)
print(f"Area of rectangle: {area}")
except (TypeError, ValueError) as e:
print(f"Error: {e}")
Enregistrez et exécutez :
python3 validate_args.py
Sortie :
Area of rectangle: 15
Error: Length must be a number
Error: Width must be positive
Cette fonction valide à la fois les types et les valeurs de ses arguments avant d'effectuer des calculs. Lorsque des arguments non valides sont détectés, des messages d'erreur appropriés sont levés.
Utilisation des assertions pour la validation
Une autre façon de valider les arguments est d'utiliser des assertions. Les assertions sont des instructions qui lèvent une AssertionError
si une condition n'est pas remplie :
def calculate_discount(price, discount_percent):
"""Calculate the discounted price."""
## Assert that inputs are valid
assert isinstance(price, (int, float)), "Price must be a number"
assert isinstance(discount_percent, (int, float)), "Discount must be a number"
assert price >= 0, "Price cannot be negative"
assert 0 <= discount_percent <= 100, "Discount must be between 0 and 100"
## Calculate the discount
discount_amount = price * (discount_percent / 100)
return price - discount_amount
## Test with valid inputs
try:
discounted_price = calculate_discount(100, 20)
print(f"Discounted price: ${discounted_price}")
except AssertionError as e:
print(f"Error: {e}")
## Test with invalid discount percentage
try:
discounted_price = calculate_discount(100, 120)
print(f"Discounted price: ${discounted_price}")
except AssertionError as e:
print(f"Error: {e}")
Enregistrez et exécutez :
python3 validate_args.py
Sortie :
Discounted price: $80.0
Error: Discount must be between 0 and 100
Les assertions sont utiles pour le développement et le débogage, mais elles peuvent être désactivées dans le code de production, elles ne sont donc pas toujours le meilleur choix pour la validation dans les applications du monde réel.
Utilisation des annotations de type pour la documentation
Python 3.5+ prend en charge les annotations de type, ce qui peut aider à documenter les types attendus des arguments de fonction et des valeurs de retour. Bien que les annotations de type n'effectuent pas de validation au moment de l'exécution par elles-mêmes, elles fournissent une documentation utile et peuvent être vérifiées par des outils externes comme mypy
:
def calculate_average(numbers: list[float]) -> float:
"""Calculate the average of a list of numbers."""
if not numbers:
raise ValueError("Cannot calculate average of empty list")
if not all(isinstance(n, (int, float)) for n in numbers):
raise TypeError("All elements must be numbers")
return sum(numbers) / len(numbers)
## Test with valid input
try:
avg = calculate_average([1, 2, 3, 4, 5])
print(f"Average: {avg}")
except (TypeError, ValueError) as e:
print(f"Error: {e}")
## Test with empty list
try:
avg = calculate_average([])
print(f"Average: {avg}")
except (TypeError, ValueError) as e:
print(f"Error: {e}")
## Test with non-numeric elements
try:
avg = calculate_average([1, 2, "3", 4, 5])
print(f"Average: {avg}")
except (TypeError, ValueError) as e:
print(f"Error: {e}")
Enregistrez et exécutez :
python3 validate_args.py
Sortie :
Average: 3.0
Error: Cannot calculate average of empty list
Error: All elements must be numbers
Notez que les annotations de type (list[float]
et -> float
) n'effectuent aucune validation par elles-mêmes - nous devons toujours écrire notre propre code de validation. Elles servent de documentation et peuvent être vérifiées par des outils externes.
Création d'une fonction robuste avec validation
Maintenant, appliquons toutes ces techniques pour créer une fonction robuste qui calcule le coût total des articles avec une remise :
def calculate_total_cost(items=None, tax_rate=0, discount=0):
"""
Calculate the total cost of items with tax and discount.
Args:
items: List of (item_name, price) tuples
tax_rate: Tax rate percentage (0-100)
discount: Discount percentage (0-100)
Returns:
A dictionary with the total, subtotal, tax amount, and discount amount
"""
## Validate items
if items is None:
items = []
if not isinstance(items, list):
raise TypeError("Items must be a list")
## Validate each item in the list
for i, item in enumerate(items):
if not isinstance(item, tuple) or len(item) != 2:
raise ValueError(f"Item {i} must be a tuple of (name, price)")
name, price = item
if not isinstance(name, str):
raise TypeError(f"Name of item {i} must be a string")
if not isinstance(price, (int, float)):
raise TypeError(f"Price of item {i} must be a number")
if price < 0:
raise ValueError(f"Price of item {i} cannot be negative")
## Validate tax_rate and discount
if not isinstance(tax_rate, (int, float)):
raise TypeError("Tax rate must be a number")
if not isinstance(discount, (int, float)):
raise TypeError("Discount must be a number")
if not (0 <= tax_rate <= 100):
raise ValueError("Tax rate must be between 0 and 100")
if not (0 <= discount <= 100):
raise ValueError("Discount must be between 0 and 100")
## Calculate the total
subtotal = sum(price for _, price in items)
discount_amount = subtotal * (discount / 100)
tax_amount = (subtotal - discount_amount) * (tax_rate / 100)
total = subtotal - discount_amount + tax_amount
return {
"subtotal": subtotal,
"discount_amount": discount_amount,
"tax_amount": tax_amount,
"total": total
}
## Test with valid inputs
shopping_cart = [
("Laptop", 1000),
("Mouse", 25),
("Keyboard", 45)
]
try:
result = calculate_total_cost(shopping_cart, tax_rate=8.5, discount=10)
print("Shopping Cart Total:")
for key, value in result.items():
print(f" {key.replace('_', ' ').title()}: ${value:.2f}")
except (TypeError, ValueError) as e:
print(f"Error: {e}")
## Test with invalid item
try:
invalid_cart = [
("Laptop", 1000),
("Mouse", "twenty-five"), ## Invalid price
("Keyboard", 45)
]
result = calculate_total_cost(invalid_cart)
print(result)
except (TypeError, ValueError) as e:
print(f"Error with invalid item: {e}")
Enregistrez et exécutez :
python3 validate_args.py
Sortie :
Shopping Cart Total:
Subtotal: $1070.00
Discount Amount: $107.00
Tax Amount: $81.86
Total: $1044.86
Error with invalid item: Price of item 1 must be a number
Cette fonction démontre une validation robuste en :
- Vérifiant les types de toutes les entrées
- Validant la plage des valeurs numériques
- Fournissant des messages d'erreur détaillés
- Définissant des valeurs par défaut raisonnables pour les paramètres optionnels
- Utilisant des docstrings pour documenter les entrées et les valeurs de retour attendues
En mettant en œuvre une validation approfondie dans vos fonctions, vous pouvez éviter les erreurs, fournir de meilleurs commentaires aux utilisateurs et rendre votre code plus robuste et maintenable.