Construire des classes et leurs comportements
object() : créer un objet minimal
object est la base commune des classes Python. Son constructeur crée un objet minimal, sans dictionnaire permettant d'y ajouter librement des attributs.
Il sert notamment à construire une valeur unique signalant une absence :
Equivalent en C#
object first = new object();
object second = new object();
Console.WriteLine(ReferenceEquals(first, second)); // False
object missing = new object();
object value = missing;
Console.WriteLine(ReferenceEquals(value, missing)); // True
new object() permet lui aussi de créer une sentinelle d’identité. Les types valeur .NET peuvent être convertis en object par boxing ; Python ne possède pas la même distinction entre types valeur et types référence.
super() : poursuivre la recherche selon l'ordre de résolution
super() fournit un intermédiaire permettant d'accéder aux implémentations suivantes dans l'ordre de résolution des méthodes (MRO). Dans un héritage simple, cela correspond généralement à la classe parente.
class Animal:
def describe(self):
return "Animal"
class Dog(Animal):
def describe(self):
return super().describe() + " : chien"
print(Dog().describe()) # Animal : chien
Ce fonctionnement est particulièrement utile pour l'héritage multiple coopératif. La forme sans argument s'emploie dans le corps approprié d'une méthode.
Equivalent en C#
Console.WriteLine(new Dog().Describe());
class Animal
{
public virtual string Describe() => "Animal";
}
class Dog : Animal
{
public override string Describe() => base.Describe() + " : chien";
}
base exprime l’accès à la classe de base en C#. Python autorise l’héritage multiple de classes et super() suit le MRO ; C# n’a qu’une classe de base directe. super() ne signifie donc pas simplement « appeler le parent nommé ».
property() : définir une propriété
property() associe l'accès à un attribut à des fonctions de lecture, d'écriture ou de suppression. On l'emploie généralement comme décorateur.
class Product:
def __init__(self, price):
self.price = price
@property
def price(self):
return self._price
@price.setter
def price(self, value):
if value < 0:
raise ValueError("Le prix doit être positif ou nul.")
self._price = value
product = Product(69.90)
print(product.price) # 69.9
La forme explicite est property(fget=None, fset=None, fdel=None, doc=None). Sans accesseur d'écriture, la propriété ne peut pas être affectée par ce mécanisme.
Equivalent en C#
var product = new Product(69.90);
Console.WriteLine(product.Price);
class Product
{
private double _price;
public Product(double price) { Price = price; }
public double Price
{
get => _price;
set
{
if (value < 0) throw new ArgumentOutOfRangeException(nameof(value));
_price = value;
}
}
}
La propriété C# get / set exprime un besoin très proche. Python s’appuie sur un objet descripteur créé par property. Les deux exemples permettent de valider une affectation ; pour des montants métier, choisissons un type décimal adapté.
classmethod() : définir une méthode de classe
Le décorateur @classmethod transmet la classe comme premier argument, nommé cls par convention. Il convient notamment aux constructeurs alternatifs.
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
@classmethod
def from_text(cls, text):
name, price = text.split(";")
return cls(name, float(price))
product = Product.from_text("Clavier;69.90")
print(product.name) # Clavier
Equivalent en C#
var product = Product.FromText("Clavier;69.90");
Console.WriteLine(product.Name);
record Product(string Name, double Price)
{
public static Product FromText(string text)
{
string[] parts = text.Split(';');
return new Product(parts[0], double.Parse(parts[1], CultureInfo.InvariantCulture));
}
}
Une fabrique statique fournit un parallèle pratique, mais ne reçoit pas automatiquement le type appelant. En Python, une méthode de classe héritée reçoit la sous-classe dans cls et peut construire celle-ci. La fabrique C# montrée construit toujours Product.
staticmethod() : définir une méthode statique
Le décorateur @staticmethod définit une méthode qui ne reçoit implicitement ni instance ni classe.
class Pricing:
@staticmethod
def calculate_total(price, tax_rate=0.20):
return price * (1 + tax_rate)
print(Pricing.calculate_total(100)) # 120.0
Une fonction de module convient aussi lorsque le rattachement à une classe n'apporte pas de sens particulier.
Equivalent en C#
Console.WriteLine(Pricing.CalculateTotal(100)); // 120
static class Pricing
{
public static double CalculateTotal(double price, double taxRate = 0.20)
=> price * (1 + taxRate);
}
static est le rapprochement direct pour une méthode sans instance. En Python, le décorateur évite l’injection implicite de self. Les règles d’appel et d’héritage ne sont pas identiques à celles des membres statiques C#.