La fonction len() est l’un des outils les plus pratiques de Python quand il faut vérifier une taille, sécuriser une boucle ou valider une donnée avant traitement. Ici, je vais aller à l’essentiel: ce que renvoie réellement cette fonction, sur quels objets elle fonctionne, pourquoi elle échoue parfois, et comment l’implémenter proprement dans vos propres classes. J’ajoute aussi les pièges que je vois le plus souvent en code réel, parce que c’est là que les erreurs coûtent du temps.
Les points essentiels à retenir sur len()
-
len()renvoie le nombre d’éléments d’un objet, pas sa taille mémoire. - Elle fonctionne sur les chaînes, listes, tuples, dictionnaires, ensembles,
rangeet d’autres conteneurs compatibles. - Un objet doit exposer
__len__()pour être pris en charge. - Les générateurs et beaucoup d’itérateurs n’ont pas de longueur connue à l’avance.
-
__len__()doit renvoyer un entier supérieur ou égal à zéro.
Ce que renvoie vraiment len()
Quand j’utilise len(), je ne cherche pas une “taille” vague. Je cherche un compteur d’éléments. Sur une liste, c’est le nombre de valeurs présentes. Sur un dictionnaire, ce sont les clés. Sur un ensemble, ce sont les éléments uniques. Sur une chaîne, c’est le nombre d’unités de texte que Python considère comme présentes dans cette chaîne.
Cette nuance compte, surtout sur les chaînes. len() ne mesure ni la place à l’écran, ni le nombre de mots, ni le poids en mémoire. Pour un texte, c’est une donnée structurelle, pas une mesure visuelle. Dans un script de traitement de contenu, c’est précisément ce qu’on veut dans la majorité des cas: savoir combien d’éléments on doit parcourir, filtrer ou valider.
texte = "Python"
nombres = [3, 8, 13]
profil = {"nom": "Amina", "role": "admin"}
print(len(texte)) # 6
print(len(nombres)) # 3
print(len(profil)) # 2Cette logique est simple, mais elle devient vite utile dès qu’on manipule des lots de données, des réponses JSON ou des listes d’objets métier. La question suivante est donc plus concrète: sur quels types Python accepte-t-il cette fonction sans surprise ?
Quels objets Python accepte sans problème
La fonction marche très bien sur les conteneurs natifs, mais pas seulement. Le plus important est de comprendre ce qu’elle compte réellement selon le type.
| Type | Ce que len() compte |
Point d’attention |
|---|---|---|
str |
Les unités de texte présentes | Ce n’est pas le nombre de mots ni la largeur affichée |
list / tuple
|
Les éléments stockés | Les éléments peuvent être de types différents |
dict |
Les clés | Une clé remplacée reste une seule entrée |
set / frozenset
|
Les éléments uniques | Les doublons sont éliminés à la création |
range |
Le nombre de valeurs générées | La longueur est calculée sans matérialiser toute la séquence |
bytes / bytearray
|
Le nombre d’octets | Ici, la notion de longueur est bien “binaire” |
Le cas de dict est souvent mal compris: len() ne compte pas les valeurs, mais les clés. Pour un set, elle reflète le nombre d’éléments réellement conservés après suppression automatique des doublons. C’est une différence simple sur le papier, mais décisive quand on valide des structures de données issues d’une API ou d’un pipeline de traitement. Une fois ce point clair, il devient plus facile de comprendre pourquoi certains objets posent problème.
Pourquoi certaines valeurs déclenchent une erreur
len() ne peut fonctionner que si Python sait déterminer une longueur logique. C’est pour cela qu’elle échoue sur beaucoup d’objets “scalaires” ou sur des flux qui ne connaissent pas leur taille à l’avance. Un entier, None, une fonction, un générateur ou un itérateur simple ne sont pas des conteneurs de longueur exploitable au sens de len().
nombre = 42
generateur = (x for x in range(5))
print(len(nombre)) # TypeError
print(len(generateur)) # TypeErrorLe piège classique, c’est de confondre itérable et mesurable par len(). Un générateur est itérable, mais il ne promet pas une taille disponible immédiatement. Si vous avez vraiment besoin du nombre d’éléments, deux stratégies existent: soit vous matérialisez la séquence avec list() si le volume reste raisonnable, soit vous comptez manuellement en consommant l’itérateur, par exemple avec sum(1 for _ in generateur). La seconde approche détruit le flux au passage, donc il faut savoir ce que l’on fait.
Il existe aussi un autre cas subtil: un objet peut être parfaitement itérable et pourtant ne pas exposer __len__(). Dans ce cas, len() refuse de deviner. Cette prudence est saine, car elle évite des résultats trompeurs dans du code qui traite des données en streaming, des fichiers ouverts ou des réponses paginées. La bonne nouvelle, c’est qu’on peut rendre ses propres objets compatibles proprement.
Rendre ses propres objets compatibles avec len()
Si je crée une classe métier, je peux lui donner une longueur en implémentant __len__(). Python appellera cette méthode quand on utilisera len() sur une instance. Le point important est simple: la méthode doit être définie sur la classe, pas ajoutée dynamiquement sur l’instance en espérant que cela suffira.
class Panier:
def __init__(self, articles):
self.articles = list(articles)
def __len__(self):
return len(self.articles)
panier = Panier(["clavier", "souris", "casque"])
print(len(panier)) # 3Cette approche est propre parce qu’elle rend la classe naturellement compatible avec les idiomes Python. Je peux alors écrire des validations, des boucles ou des contrôles de capacité sans créer de logique spéciale autour de l’objet. En pratique, c’est aussi ce qui améliore la lisibilité pour les autres développeurs de l’équipe.
Deux règles méritent d’être gardées en tête. D’abord, __len__() doit renvoyer un entier supérieur ou égal à zéro. Ensuite, si votre classe ne définit pas __bool__(), Python peut utiliser la longueur pour déterminer sa vérité logique: une longueur nulle sera interprétée comme False. C’est souvent utile, mais il faut le savoir pour éviter les comportements surprenants dans les tests conditionnels.
Les pièges qui coûtent du temps en débogage
Sur le terrain, je retrouve toujours les mêmes confusions. Elles ne sont pas spectaculaires, mais elles font perdre du temps parce qu’elles ressemblent à des bugs de logique alors qu’il s’agit juste d’un mauvais usage de la fonction.
| Erreur courante | Pourquoi c’est trompeur | Bon réflexe |
|---|---|---|
Utiliser len() pour compter les mots d’une phrase |
La fonction compte les caractères ou éléments, pas les mots | Découper le texte avec split() ou une logique adaptée |
Appeler len() sur un générateur |
La taille n’est pas connue sans consommation du flux | Itérer, matérialiser ou compter explicitement |
| Confondre chaîne visible et unités de texte | Un symbole affiché peut être composé de plusieurs éléments Unicode | Ne pas confondre longueur technique et rendu visuel |
Penser que len() mesure la mémoire occupée |
La fonction ne donne pas la taille en octets de l’objet Python | Utiliser des outils de profilage mémoire si c’est l’objectif |
Il y a aussi une subtilité de performance: sur les conteneurs natifs, len() est généralement très rapide, parce que Python connaît déjà la taille. En revanche, pour un objet personnalisé, tout dépend de votre implémentation de __len__(). Si vous la faites recalculer un total coûteux à chaque appel, vous transformez une opération simple en point chaud du programme. C’est souvent invisible au début, puis très pénalisant à mesure que les volumes grandissent.
Le bon réflexe avant d’utiliser len() dans un projet réel
Quand je dois décider entre len(obj) > 0 et if obj:, je choisis presque toujours la forme la plus lisible pour l’intention du code. Si je veux savoir si une collection est vide, le test de vérité est souvent plus direct. Si je veux un nombre précis à afficher, journaliser ou comparer, len() est le bon outil.
Dans un projet sérieux, ce petit choix a un effet concret: il clarifie le contrat de la donnée. Est-ce que je vérifie une présence, une capacité, une limite ou un volume? La réponse dicte la bonne formulation. Et dans les systèmes qui manipulent beaucoup de données, cette clarté vaut autant que la syntaxe elle-même.
- Utilisez
len()pour obtenir un compteur explicite. - Utilisez un test de vérité pour vérifier si une structure est vide ou non.
- Évitez
len()sur les flux si la taille n’est pas disponible sans parcours complet. - Dans vos classes, faites de
__len__()un calcul fiable, rapide et cohérent.
En pratique, la fonction devient plus utile quand on la traite comme une convention de structure plutôt que comme un simple raccourci. C’est exactement ce qui la rend si présente dans le code Python moderne: elle est petite, mais elle dit beaucoup sur la forme réelle des données.