Python >> Tutoriel Python >  >> Python

Comment résoudre Python "TypeError:l'objet 'int' n'est pas itérable" ?

Il est assez courant que votre code lance un typeerror , surtout si vous débutez avec Python. La raison en est que l'interpréteur attend des variables de certains types à certains endroits dans le code.

Nous allons examiner un exemple spécifique d'une telle erreur :"typeerror: 'int' object is not iterable" .

Exercice  :Exécutez cet exemple minimal et reproduisez l'erreur dans votre shell Python en ligne !

Commençons à décomposer cette erreur étape par étape !

Entier d'arrière-plan et itérable

Tout d'abord, il est utile de comprendre ce que int et iterable sont.

Le int type en Python, comme dans presque tous les langages de programmation, est un type pour stocker des entiers tels que 1, 2, 3, -324, 0. Il peut y avoir de nombreuses variables de type int dans notre programme. Nous pouvons leur attribuer nous-mêmes directement des valeurs :

a = 5

Dans ce cas, on comprendra le plus souvent ce qu'est un type de notre variable. Mais la valeur peut, par exemple, être renvoyée par une fonction. Python utilise le typage implicite . Le typage implicite signifie que lors de la déclaration d'une variable, vous n'avez pas besoin de spécifier son type; quand explicitement, vous devez. Par conséquent, en affectant le résultat d'une fonction à une variable, vous ne savez peut-être pas clairement de quel type sera votre variable.

s1 = sum([1, 2, 3])
print(s1)
print(type(s1))

Sortie :

6
<class 'int'>

Voici un autre exemple :

s2 = iter([1, 2, 3])
print(s2)
print(type(s2))

Sortie :

<list_iterator object at 0x7fdcf416eac8>
<class 'list_iterator'>

Dans cet exemple, s1 est un entier et est de type int . Ce nombre est renvoyé par le sum fonction avec un argument sous la forme d'une liste de 3 éléments. Et la variable s2 est de type list_iterator , un objet de ce type est retourné par le iter fonction, dont l'argument est la même liste de 3 éléments. Nous allons parler d'itération maintenant.

L'itération est un terme général qui décrit la procédure pour prendre les éléments de quelque chose à tour de rôle.

Plus généralement, il s'agit d'une séquence d'instructions qui est répétée un nombre de fois spécifié ou jusqu'à ce qu'une condition spécifiée soit remplie.

Un itérable est un objet qui est capable de renvoyer des éléments un par un. C'est aussi un objet à partir duquel obtenir un itérateur.

Exemples d'objets itérables :

  • toutes les séquences :liste, chaîne, tuple
  • dictionnaires
  • fichiers

Il semble que le moyen le plus simple de savoir exactement ce que notre fonction renvoie est de consulter la documentation.

On voit donc pour l'iter :iter(object[, sentinel]) Renvoie un objet itérateur.

Mais pour la somme, nous n'avons rien sur un type de valeur de retour. Vérifiez-le par vous-même !

Donc, le typeerror: ‘int’ object is not iterable L'erreur se produit lorsque l'interpréteur attend un objet itérable et reçoit juste un entier. Considérons les exemples les plus courants de tels cas.

Argument "somme" invalide

Nous avons déjà parlé de la fonction somme. Il renvoie la valeur int. La fonction somme prend au plus deux arguments. Le premier argument doit être un objet itérable. S'il s'agit d'une collection quelconque, alors c'est probablement une hypothèse sûre qu'elle est itérable. Le deuxième argument de la fonction somme est facultatif. C'est un nombre qui représente le premier nombre auquel vous commencerez à ajouter. Si vous omettez le deuxième argument, vous commencerez à ajouter à 0. Pour les programmeurs Python novices, il semble logique qu'une fonction renvoie la somme de ses arguments. Souvent, ils essaient de l'appliquer comme ceci :

a = 4
b = 3
sum(a, b)

Sortie :

TypeError Traceback (most recent call last)

<ipython-input-12-35b280174f65> in <module>()
      1 a = 4
      2 b = 3
----> 3 sum(a, b)

TypeError: 'int' object is not iterable

Mais on voit que cela conduit à une erreur. Nous pouvons résoudre cette situation en pré-écrivant nos variables pour la sommation dans un objet itérable, dans une liste ou un tuple, ou un ensemble, par exemple :

a = 4
b = 3

tuple_sum = (a, b)
list_sum = [a, b]
set_sum = {a, b}
dict_sum = {a: 0, b: 1}

print(sum(tuple_sum))
print(sum(list_sum))
print(sum(set_sum))
print(sum(dict_sum))

Sortie :

7
7
7
7

Comme vous pouvez le voir, le résultat reste le même. Que nous utilisions la pré-entrée dans un tuple, une liste, un ensemble ou même un dictionnaire. Notez que pour les dictionnaires, la fonction sum additionne les valeurs clés par défaut.

Vous pouvez même écrire une variable dans une liste et calculer la somme de cette liste. Comme le montre une recherche sur stackoverflow, les débutants en programmation essaient souvent de calculer la somme d'un élément, ce qui conduit bien sûr à une erreur.

a = 2
sum(a)

Sortie :

TypeError                                 Traceback (most recent call last)

<ipython-input-21-5db7366faaa2> in <module>()
      1 a = 2
----> 2 sum(a)

TypeError: 'int' object is not iterable

Mais si nous passons un objet itérable, par exemple une liste (même si elle se compose d'un élément) à la fonction, le calcul est réussi.

a = 2
list_sum = [a]
print(sum(list_sum))

Sortie :

2

Une autre façon de former une telle liste est d'utiliser le list.append méthode :

a = 2
list_sum = []
list_sum.append(a)
print('Sum of "a":', sum(list_sum))
b = 5
list_sum.append(b)
print('Sum of "a" and "b":',sum(list_sum))

Sortie :

'''
Sum of "a": 2
Sum of "a" and "b": 7
'''

Considérons une version plus complexe de la même erreur. Nous avons une fonction qui doit calculer la somme des éléments de la liste incluant les éléments des listes imbriquées.

def nested_sum(list_):
    total = 0
    for item in list_:
       item = sum(item)
       total = total + item
    return total
list1 = [1, 2, 3, [4, 5]]
print(nested_sum(list1))

Sortie :

TypeError                                 Traceback (most recent call last)

<ipython-input-35-c30be059e3a4> in <module>()
      6     return total
      7 list1 = [1, 2, 3, [4, 5]]
----> 8 nested_sum(list1)

<ipython-input-35-c30be059e3a4> in nested_sum(list_)
      2     total = 0
      3     for item in list_:
----> 4        item = sum(item)
      5        total = total + item
      6     return total

TypeError: 'int' object is not iterable

Vous pouvez probablement déjà voir quel est le problème ici. La boucle analyse la liste en ses éléments et les parcourt. Les éléments de notre liste sont les numéros 1, 2, 3 et une liste [4, 5] . Vous pouvez calculer une somme de la liste mais vous ne pouvez pas obtenir la somme d'un nombre en Python. Nous devons donc réécrire le code.

def nested_sum(list_):
    total = 0
    for item in list_:
      if type(item) == list:
        item = sum(item)
      total = total + item
    return total
list1 = [1, 2, 3, [4, 5]]
print(nested_sum(list1))

Sortie :

15

Maintenant, dans la boucle, nous vérifions tout d'abord le type de notre variable locale 'item' et si c'est une liste, alors en toute conscience on calcule sa somme et on réécrit la variable 'item' avec la valeur obtenue. S'il ne s'agit que d'un seul élément, nous ajoutons sa valeur au 'total' .

Utilisation incorrecte de la boucle "for"

Considérons un autre cas courant de cette erreur. Pouvez-vous voir immédiatement d'où vient le problème ?

n = 10
for i in n:
  print(i)

Sortie :

TypeError                                 Traceback (most recent call last)

<ipython-input-24-7bedb9f8cc4c> in <module>()
      1 n = 10
----> 2 for i in n:
      3   print(i)

TypeError: 'int' object is not iterable

Peut-être que l'erreur dans cette construction est associée à la tradition d'enseigner aux enfants la langue pascal à l'école. Là, vous pouvez en fait écrire quelque chose de similaire :for i:=1 to n do .

Mais en Python, les boucles "for" sont utilisées pour le parcours séquentiel. Leur construction suppose la présence d'un objet itérable. Dans d'autres langages, une construction "pour chaque" est généralement utilisée pour un tel parcours.

Ainsi, la construction 'for' en Python attend un objet itérable qui doit être traversé et ne peut pas interpréter un entier. Cette erreur peut être facilement corrigée à l'aide de la fonction "gamme". Voyons à quoi ressemblerait notre exemple dans ce cas.

n = 10
for i in range(n):
  print(i)

Sortie :

0
1
2
3
4
5
6
7
8
9

La fonction 'range' peut prendre 3 arguments comme ceci : range(start, stop[, step]) . Le « start » est le premier numéro à partir duquel la boucle commencera, « stop » est le numéro auquel la boucle se terminera. Veuillez noter que le numéro « stop » ne sera pas inclus dans le cycle. Le «pas» est de combien le nombre différera à chaque itération suivante de la précédente. Par défaut, ‘start’ vaut 0, ‘step’=1, et le paramètre stop doit être obligatoirement passé. Plus de détails avec des exemples peuvent être trouvés dans la documentation. https://docs.python.org/3.3/library/stdtypes.html?highlight=range#range

for i in range(4, 18, 3):
  print(i)

Sortie :

4
7
10
13
16

Voici un petit exemple d'utilisation des trois paramètres de la fonction "range". Dans la boucle, la variable "i" de la première étape sera égale à 4, "i" ne sera jamais supérieure ou égale à 18 et augmentera par incréments de 3.

Problèmes avec les tuples

L'exemple suivant où une erreur "typeerror: ‘int’ object is not iterable" peut se produire est une affectation multiple de valeurs à l'aide d'un tuple. Prenons un exemple.

a, b = 0

Sortie :

---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-6-6ffc3a683bb5> in <module>()
----> 1 a, b = 0

TypeError: 'int' object is not iterable

C'est une méthode d'affectation très pythonique, mais vous devez y faire attention. Sur la gauche, nous voyons un tuple de deux éléments « a » et « b », donc à droite du signe égal, il doit également y avoir un tuple (ou tout autre objet itérable) de deux éléments. Ne soyez pas intimidé en écrivant un tuple sans parenthèses, c'est un moyen autorisé en Python.

Donc, pour corriger cette erreur, nous pouvons écrire le devoir comme ceci :

a, b = 0, 0
print(a)
print(b)

Sortie :

0
0

Et quelques autres exemples de la façon dont vous pouvez attribuer des valeurs à plusieurs variables à la fois :

a, b = (1, 2)
c, d = {3, 4}
e, f = [5, 6]
print(a, b, c ,d ,e, f)

Sortie :

1 2 3 4 5 6

Un problème similaire peut survenir si vous utilisez une fonction qui renvoie plusieurs valeurs sous forme de tuple. Considérons, par exemple, une fonction qui renvoie la somme, le produit et le résultat de la division de deux nombres.

def sum_product_division(a, b):
  if b != 0:
    return a + b, a * b, a / b
  else:
    return -1

sum_, product, division = sum_product_division(6, 2)
print("The sum of numbers is:", sum_)
print("The product of numbers is:", product)
print("The division of numbers is:", division)

Sortie :

The sum of numbers is: 8
The product of numbers is: 12
The division of numbers is: 3.0

Notez que j'ai ajouté un trait de soulignement au nom de la variable 'sum_'. C'est parce que le mot 'somme' est le nom de la fonction intégrée dont nous avons discuté ci-dessus. Comme vous pouvez le voir, dans le cas où 'b' n'est pas égal à zéro, notre code fonctionne correctement, les variables prennent les valeurs appropriées. Essayons maintenant de passer la valeur 'b' égale à 0 à la fonction. La division par zéro ne se produira pas, puisque nous l'avons prévu dans la fonction et renvoyons -1 comme code d'erreur.

sum_, product, division = sum_product_division(6, 0)
print("The sum of numbers is:", sum_)
print("The product of numbers is:", product)
print("The division of numbers is:", division)

Sortie :

---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-9-6c197be50200> in <module>()
----> 1 sum_, product, division = sum_product_division(6, 0)
      2 print("The sum of numbers is:", sum_)
      3 print("The product of numbers is:", product)
      4 print("The division of numbers is:", division)

TypeError: 'int' object is not iterable

L'erreur "TypeError: 'int' object is not iterable » se reproduit. Quel est le problème? Comme je l'ai déjà dit, cette situation est similaire à la précédente. Ici, nous essayons également d'attribuer des valeurs à plusieurs variables à l'aide d'un tuple. Mais notre fonction lorsqu'il y a un danger de division par zéro ne retourne pas un tuple mais la seule valeur du code d'erreur '-1'.

Comment le réparer? Par exemple, nous pouvons vérifier le type d'une valeur renvoyée. Et selon ce type, affichez déjà le résultat. Allons-y !

result = sum_product_division(6, 0)
if type(result) == int:
  print("Error, b should not be zero!")
else:
  sum_, product, division = result
  print("The sum of numbers is:", sum_)
  print("The product of numbers is:", product)
  print("The division of numbers is:", division)

Sortie :

Error, b should not be zero!

Voici un autre exemple :

result = sum_product_division(6, 3)
if type(result) == int:
  print("Error, b should not be zero!")
else:
  sum_, product, division = result
  print("The sum of numbers is:", sum_)
  print("The product of numbers is:", product)
  print("The division of numbers is:", division)

Sortie :

The sum of numbers is: 9
The product of numbers is: 18
The division of numbers is: 2.0

Nous pouvons également reconcevoir notre fonction pour renvoyer le résultat de l'opération depuis le début du tuple. Et utilisez une astuce lors de l'affectation de variables. Jetez un oeil à ceci :

def sum_product_division(a, b):
  if b != 0:
    return "Ok", a + b, a * b, a / b
  else:
    return ("Error",)

status, *results = sum_product_division(6, 0)
print(status, results)

status, *results = sum_product_division(6, 2)
print(status, results)

Sortie :

Error []
Ok [8, 12, 3.0]

Si la division par zéro est possible, nous renvoyons un tuple avec un seul élément - la chaîne 'Error'. Si tout est correct, nous renvoyons un tuple où le premier élément est un message d'état - la chaîne "Ok", puis les résultats des calculs suivent séquentiellement :somme, produit, résultat de la division.

Il peut y avoir de nombreuses options ici, car c'est une fonction que nous avons écrite nous-mêmes, nous pouvons donc la corriger à notre guise. Mais il se trouve que nous utilisons des fonctions de bibliothèques. Par exemple, voici une erreur d'un sujet sur stackoverflow.

import subprocess
data = subprocess.call(["echo", '''Hello World!
Hello!'''])
sum_lines = 0
for line in data:
  print(line)
  sum_lines += 1
print(sum_lines)

Sortie :

---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-32-8d4cf2cb9ee0> in <module>()
      3 Hello!'''])
      4 sum_lines = 0
----> 5 for line in data:
      6   print(line)
      7   sum_lines += 1

TypeError: 'int' object is not iterable

J'ai un peu réécrit le code pour que l'essentiel soit clair. Nous voulons exécuter une commande sur la ligne de commande et compter le nombre de lignes imprimées à l'écran. Dans notre cas, ce sera juste une commande pour afficher un petit message au Monde.

Nous devrions lire une documentation pour le comprendre. Le module de sous-processus vous permet de générer de nouveaux processus, de vous connecter à leurs canaux d'entrée/sortie/erreur et d'obtenir leurs codes de retour. On voit que la fonction 'call' lance le processus en ligne de commande, puis attend son exécution et retourne le code résultat de l'exécution ! C'est ça! La fonction a renvoyé le code d'exécution. C'est un entier et nous essayons de parcourir cet entier dans une boucle. Ce qui est impossible, comme je l'ai décrit ci-dessus.

Que faire? Explorez plus en détail la documentation du module. Et ainsi nous trouvons ce dont nous avons besoin. La fonction ‘check_output’. Il renvoie tout ce qui doit être affiché dans la console lorsque la commande passée est exécutée. Découvrez comment cela fonctionne :

import subprocess
data=subprocess.check_output(["echo", '''Hello World!
Hello!'''])
sum_lines = 0
for line in data.splitlines():
        print(line)
        sum_lines +=1
print(sum_lines)

Sortie :

b'Hello World!'
b'Hello!'
2

Super! Nous avons obtenu une chaîne d'octets séparés par des symboles de nouvelle ligne '\ n' à la sortie. Et nous pouvons le parcourir comme indiqué avec une fonction "splitlines". Il renvoie une liste des lignes de la chaîne, s'interrompant aux limites des lignes. Cette méthode utilise l'approche universelle des nouvelles lignes pour diviser les lignes. Les sauts de ligne ne sont pas inclus dans la liste résultante à moins que le paramètre 'keepends' soit donné et vrai.

Ainsi, nous avons corrigé l'erreur et obtenu ce dont nous avions besoin, mais nous avons dû faire une petite recherche dans la documentation. Cette étude de la documentation est l'un des moyens les plus efficaces d'améliorer vos compétences en programmation.

Le hic avec les listes

Souvent l'erreur "TypeError: 'int' object is not iterable" apparaît lors de l'utilisation de diverses fonctions liées aux listes. Par exemple, j'ai une liste de mes notes d'examen. Je veux y ajouter une note en éducation physique que j'ai parfaitement réussi contrairement aux mathématiques. J'essaie de le faire comme ceci :

grades = [74, 85, 61]
physical_education_mark = 100
grades += physical_education_mark

J'utilise la méthode la plus conventionnelle pour effectuer la concaténation de la liste, l'utilisation de l'opérateur "+". Il peut facilement ajouter l'ensemble d'une liste derrière l'autre liste et donc effectuer la concaténation. Mais ça ne marche pas ici. Parce que la concaténation de listes n'est possible que pour deux listes. Nous ne pouvons pas combiner liste et nombre. La façon la plus évidente de résoudre ce problème est d'utiliser la fonction "append". Il est conçu juste pour faire ça. Il ajoute un élément à la liste. L'argument peut également être un entier.

grades = [74, 85, 61]
physical_education_mark = 100
grades.append(physical_education_mark)
print(grades)

Sortie :

[74, 85, 61, 100]

Voila ! Nous l'avons fait! Bien sûr, si nous voulons vraiment utiliser l'opérateur "+", nous pouvons pré-écrire notre note d'éducation physique dans une liste avec un élément, par exemple comme ceci :

grades = [74, 85, 61]
physical_education_mark = 100
grades += [physical_education_mark]
print(grades)

Sortie :

[74, 85, 61, 100]

On s'attend à ce que le résultat soit le même que le précédent. Continuez.

Un autre problème lié à la liste est lorsque vous essayez d'ajouter un élément avec la méthode "extend". Cette méthode peut être très utile pour concaténer des listes. Contrairement à l'opérateur "+", il change la liste à partir de laquelle il est appelé. Par exemple, je dois ajouter de nouvelles notes de semestre à la liste des notes. C'est facile à faire avec la méthode "extend":

grades = [74, 85, 61]
new_semestr_grades = [85, 79]
physical_education_mark = 100
grades.extend(new_semestr_grades)
print(grades)

Sortie :

[74, 85, 61, 85, 79]

Alors on l'a fait facilement mais attendez ! On a oublié notre score parfait en éducation physique !

grades = [74, 85, 61]
new_semestr_grades = [85, 79]
physical_education_mark = 100
grades.extend(new_semestr_grades)
grades.extend(physical_education_mark)
print(grades)

Sortie :

---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-48-6d49503fc731> in <module>()
      3 physical_education_mark = 100
      4 grades.extend(new_semestr_grades)
----> 5 grades.extend(physical_education_mark)
      6 print(grades)

TypeError: 'int' object is not iterable

Et on ne peut pas faire comme ça. 'extend' attend un objet itérable comme argument. Nous pouvons utiliser la méthode "append" ou la méthode de pré-écriture.

grades = [74, 85, 61]
new_semestr_grades = [85, 79]
physical_education_mark = [100]
grades.extend(new_semestr_grades)
grades.extend(physical_education_mark)
print(grades)

Sortie :

[74, 85, 61, 85, 79, 100]

Avez-vous remarqué la différence? J'ai initialement défini la variable « physical_education_mark » comme une liste avec un élément. Et cela fonctionne parfaitement !

Supposons maintenant que nous ayons besoin d'une fonction qui trouvera l'emplacement des variables dans la formule "A + C =D - 6". Si vous savez que chaque variable de la formule est désignée par une lettre majuscule. Nous essayons de l'écrire :

def return_variable_indexes(formula):
  for element in formula:
    if element.isupper():
      indexes = list(formula.index(element))
  return indexes

print(return_variable_indexes("A + C = D - 6"))

Sortie :

---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-44-5a9b17ff47ae> in <module>()
      5   return indexes
      6 
----> 7 print(return_variable_indexes("A + C = D - 6"))

<ipython-input-44-5a9b17ff47ae> in return_variable_indexes(formula)
      2   for element in formula:
      3     if element.isupper():
----> 4       indexes = list(formula.index(element))
      5   return indexes
      6 

TypeError: 'int' object is not iterable

Oui, nous avons encore la même erreur. Essayons de comprendre de quoi il s'agit. Nous passons en revue les éléments de la chaîne ‘formule’. Et si cet élément est une lettre majuscule, nous utilisons la fonction 'index' pour trouver sa position dans la chaîne. Et essayez de l'écrire dans une liste "index". Nous avons donc deux fonctions ‘index’ et ‘list’. Quelle est la valeur de retour de la fonction 'index' ? C'est un nombre entier la position à la première occurrence de la valeur spécifiée. Nous essayons donc d'ajouter ceci à la liste des "index" avec une fonction "liste". Et arrêtez-vous ici ! Le constructeur ‘list’ prend un argument. Il doit s'agir d'un objet itérable, de sorte qu'il peut s'agir d'une séquence (chaîne, tuples) ou d'une collection (ensemble, dictionnaire) ou de tout objet itérateur. Pas un nombre entier bien sûr. Nous pouvons donc utiliser à nouveau la méthode "append" et obtenir le résultat dont nous avons besoin :

def return_variable_indexes(formula):
  indexes = []
  for element in formula:
    if element.isupper():
      indexes.append(formula.index(element))
  return indexes

print(return_variable_indexes("A + C = D - 6"))

Sortie :

[0, 4, 8]

Et juste pour le plaisir, vous pouvez le faire en une seule ligne en utilisant une compréhension de liste et la méthode "énumérer". Il prend un objet itérable comme argument et renvoie ses éléments avec index sous forme de tuples (index, élément) un tuple par un autre :

def return_variable_indexes(formula):
  return [index_ for index_, element in enumerate(formula) if element.isupper()]
print(return_variable_indexes("A + C = D - 6"))

Sortie :

[0, 4, 8]

Conclusion

Nous avons examiné certains cas dans lesquels une erreur "TypeError:l'objet 'int' n'est pas itérable" se produit. C'est toujours une situation où l'interpréteur attend un itérable objet, et nous lui fournissons un entier .

Les cas les plus courants de telles erreurs :

  • argument de somme incorrect ;
  • gestion incorrecte des tuples ;
  • lié à diverses fonctions et méthodes de listes

J'espère qu'après avoir lu cet article, vous n'aurez jamais un problème similaire. Et si cela survient soudainement, vous pouvez facilement le résoudre. Vous devrez peut-être lire la documentation pour cela =)