Examiner les types et les objets
type() : obtenir un type ou créer une classe
La forme courante renvoie le type exact d'un objet.
Une forme avancée permet de construire une classe à partir de son nom, de ses bases et de son espace de noms :
Product = type("Product", (), {"category": "Informatique"})
print(Product().category) # Informatique
Equivalent en C#
object value = 42;
Console.WriteLine(value.GetType() == typeof(int)); // True
Console.WriteLine(typeof(string).Name); // String
GetType() donne le type d’un objet non nul ; typeof(T) désigne un type connu à la compilation. La création dynamique de classes avec type(name, bases, namespace) se rapproche de Reflection.Emit, sans équivalent aussi direct. ExpandoObject ajoute des membres dynamiques à un objet, sans créer une nouvelle classe CLR.
isinstance() : tester l'appartenance à un type
isinstance() tient compte de l'héritage. Pour tester la compatibilité d'un objet avec une classe, elle est généralement préférable à une comparaison directe avec type().
print(isinstance(42, int)) # True
print(isinstance(3.5, (int, float))) # True
print(isinstance(True, int)) # True : bool dérive de int
Equivalent en C#
object value = 42;
Console.WriteLine(value is int); // True
object flag = true;
Console.WriteLine(flag is int); // False
Le mot-clé is teste la compatibilité de type en tenant compte de l’héritage et des interfaces. Contrairement à Python, bool ne dérive pas de int en C#.
issubclass() : tester une relation d'héritage
class Animal:
pass
class Dog(Animal):
pass
print(issubclass(Dog, Animal)) # True
print(issubclass(Animal, Animal)) # True
Le premier argument doit être une classe, pas une instance.
Equivalent en C#
Console.WriteLine(typeof(Dog).IsSubclassOf(typeof(Animal))); // True
Console.WriteLine(typeof(Animal).IsSubclassOf(typeof(Animal))); // False
Console.WriteLine(typeof(Animal).IsAssignableFrom(typeof(Animal))); // True
class Animal { }
class Dog : Animal { }
IsSubclassOf() exclut le type lui-même. IsAssignableFrom() inclut ce cas et les compatibilités d’interface ; son sens d’appel est inversé par rapport à issubclass(Dog, Animal). Les modèles d’héritage des deux langages ne sont pas identiques.
callable() : tester si un objet peut être appelé
Un résultat True ne garantit pas le succès de n'importe quel appel : les arguments doivent notamment convenir.
Equivalent en C#
object action = (Action)(() => Console.WriteLine("Bonjour"));
Console.WriteLine(action is Delegate); // True
Tester Delegate couvre les délégués, mais pas tout ce qui ressemble à un appel en Python. Une classe Python est appelable pour construire une instance ; en C#, cette construction passe normalement par new. Il n’existe pas de test général strictement équivalent à callable().
id() : obtenir l'identité d'un objet
id() renvoie un entier identifiant l'objet pendant sa durée de vie. Deux objets qui existent simultanément ont des identités différentes.
first = [1, 2]
second = first
third = [1, 2]
print(id(first) == id(second)) # True
print(first is second) # True
print(first is third) # False
print(first == third) # True
Une identité peut être réutilisée après la disparition de l'objet. Elle ne constitue pas un identifiant persistant.
Equivalent en C#
var first = new List<int> { 1, 2 };
var second = first;
var third = new List<int> { 1, 2 };
Console.WriteLine(ReferenceEquals(first, second)); // True
Console.WriteLine(ReferenceEquals(first, third)); // False
Console.WriteLine(first.SequenceEqual(third)); // True
Pour comparer des identités de références, utilisons ReferenceEquals(). .NET ne fournit pas ici d’entier d’identité unique analogue à id(). Un hachage d’identité peut entrer en collision et ne doit pas être utilisé comme identifiant unique. Pour les types valeur, le boxing rend ce rapprochement inadapté.
hash() : obtenir une valeur de hachage
hash() renvoie le hachage d'un objet hachable. Les dictionnaires et les ensembles utilisent ce mécanisme pour organiser leurs recherches.
Deux objets égaux doivent avoir le même hachage ; deux objets distincts peuvent partager un hachage. Une liste n'est pas hachable. Le résultat, notamment pour les chaînes, n'est pas destiné à rester identique entre plusieurs exécutions. Ce n'est pas une empreinte cryptographique.
Equivalent en C#
Console.WriteLine(42.GetHashCode());
Console.WriteLine((1, 2).GetHashCode() == (1, 2).GetHashCode()); // True
GetHashCode() joue un rôle similaire pour les collections de hachage. Il n’est ni unique ni persistant. Une collection .NET peut être utilisable comme clé avec une égalité de référence, sans égalité structurelle par contenu. Les listes Python, elles, ne sont pas hachables.
dir() : explorer les noms disponibles
Sans argument, dir() liste des noms de la portée locale. Avec un objet, elle aide à découvrir ses attributs et méthodes.
La liste est une aide à l'exploration ; elle n'est pas nécessairement exhaustive pour les objets qui personnalisent l'accès à leurs attributs.
Equivalent en C#
var names = typeof(string).GetMembers().Select(member => member.Name).Distinct();
Console.WriteLine(names.Contains("ToUpper")); // True
La réflexion permet d’examiner les membres du type CLR. Elle n’équivaut pas à la découverte personnalisable des attributs Python. GetMembers() avec ses options par défaut expose principalement les membres publics.
vars() : accéder au dictionnaire d'attributs
Avec un objet, vars() renvoie son attribut __dict__ s'il existe.
class Product:
def __init__(self, name):
self.name = name
print(vars(Product("Clavier"))) # {'name': 'Clavier'}
Certains objets n'ont pas de __dict__ et provoquent TypeError. Sans argument, vars() se comporte comme locals().
Equivalent en C#
var product = new { Name = "Clavier", Price = 69.90 };
var values = product.GetType().GetProperties()
.ToDictionary(p => p.Name, p => p.GetValue(product));
Console.WriteLine(values["Name"]); // Clavier
Cette projection construit un nouveau dictionnaire de propriétés publiques. Ce n’est pas le dictionnaire interne de l’objet : modifier values ne modifie pas product. Les appels aux getters peuvent exécuter du code.