Définir des modèles de données
dataclasses : classes centrées sur les données
Le décorateur @dataclass peut générer notamment __init__(), __repr__() et __eq__() à partir des champs déclarés.
from dataclasses import dataclass, field, asdict
@dataclass
class Product:
name: str
price: float
tags: list[str] = field(default_factory=list)
product = Product("Clavier", 69.90)
print(asdict(product))
# {'name': 'Clavier', 'price': 69.9, 'tags': []}
default_factory crée une nouvelle liste pour chaque instance. replace() construit une autre instance en modifiant certains champs. frozen=True bloque les affectations usuelles aux champs, sans rendre immuables tous les objets qu'ils contiennent. Les annotations ne valident pas automatiquement les valeurs à l'exécution.
Parallèle C# et .NET
var product = new Product("Clavier", 69.90);
var other = product with { Price = 79.90 };
Console.WriteLine(other.Name);
public record Product(string Name, double Price)
{
public List<string> Tags { get; init; } = new();
}
Un record C# génère une représentation et une égalité centrées sur les données. with crée une copie superficielle : Tags reste partagé ici. Les deux modèles ne sont pas identiques ; notamment l’égalité des listes est structurelle en Python, mais repose par défaut sur la référence des List<T> en C#. asdict() n’a pas de correspondance automatique dans ce record.
enum : ensembles de valeurs nommées
from enum import Enum, auto
class OrderStatus(Enum):
CREATED = auto()
PAID = auto()
SHIPPED = auto()
status = OrderStatus.PAID
print(status.name) # PAID
print(status is OrderStatus.PAID) # True
Enum définit les membres et auto() demande une valeur automatique. IntEnum s'intègre aux entiers ; Flag sert aux combinaisons de drapeaux. Une énumération permet de remplacer des chaînes dispersées par des valeurs explicites.
Parallèle C# et .NET
OrderStatus status = OrderStatus.Paid;
Console.WriteLine(status); // Paid
Console.WriteLine(status == OrderStatus.Paid); // True
enum OrderStatus
{
Created = 1,
Paid = 2,
Shipped = 3
}
Les valeurs commencent explicitement à 1 pour correspondre à l’usage courant de auto() dans Enum Python ; un enum C# sans initialisation commence à 0. C# autorise par cast des valeurs numériques non déclarées. [Flags] se rapproche de Flag, mais les règles de typage et d’opérations restent différentes.
typing : préciser les contrats de types
typing fournit notamment Any, Literal, TypedDict, Protocol et cast() pour les annotations et l'analyse statique.
from typing import TypedDict, Literal
class ProductData(TypedDict):
name: str
category: Literal["hardware", "software"]
product: ProductData = {"name": "Clavier", "category": "hardware"}
print(product["name"])
À l'exécution, cet objet reste un dictionnaire ordinaire. Un analyseur comme Mypy peut vérifier le contrat ; Python ne le contrôle pas automatiquement. Pour les collections usuelles, préférons les formes modernes list[str], dict[str, int] et str | None plutôt que les anciens alias correspondants.
Parallèle C# et .NET
var product = new ProductData("Clavier", ProductCategory.Hardware);
Console.WriteLine(product.Name);
public enum ProductCategory { Hardware, Software }
public record ProductData(string Name, ProductCategory Category);
Le contrat est ici un type CLR réel, vérifié principalement par le compilateur. Un TypedDict Python reste un dictionnaire à l’exécution. Protocol utilise un typage structurel dans les outils d’analyse ; une interface C# exige normalement une implémentation déclarée. typing.cast() ne convertit pas la valeur à l’exécution, contrairement à de nombreux casts C#.