Etrange message d'erreur Python —— Ce code est-il vraiment exécuté?

Message d'erreur étrange, que se passe-t-il?

Dans un répertoire sur une machine, j'ai tapé ʻeval ("1/0") ʻen Python interactif (CPython).

Python 3.5.3 (default, Jan 19 2017, 14:11:04) 
[GCC 6.3.0 20170118] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> eval("1/0")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
Dois-je me coucher bientôt?
  File "<string>", line 1, in <module>
C'est déjà la limite, non?
ZeroDivisionError: division by zero

Je vois, une erreur d'exécution avec zéro division, ce qui est comme prévu. Mais, "Pourquoi n'allez-vous pas vous coucher bientôt?" "C'est déjà la limite." Qu'est-ce que c'est?

Python sur cette machine n'a pas été modifié, tout comme les bibliothèques standard. Aucun programme n'a été écrit pour provoquer ce phénomène. Quelle pourrait-être la cause?

S'il y a une erreur lors de l'exécution du fichier source, le code correspondant sera affiché

Éloignez-vous de la machine avec des messages étranges et vérifiez la nature de Traceback qui s'affiche lorsqu'une erreur se produit. Tout d'abord, essayez d'exécuter le fichier source hello.py qui provoque une division nulle.

hello.py


print(1/0)
$ python3 hello.py
Traceback (most recent call last):
  File "hello.py", line 1, in <module>
    print(1/0)
ZeroDivisionError: division by zero

Le traçage montre que l'erreur s'est produite sur la ligne «print (1/0)». C'est le comportement attendu.

Le code de la partie d'erreur est obtenu après que l'erreur se soit produite

Comme indiqué ci-dessus, il est pratique de voir le code source qui a causé l'erreur dans Traceback, mais comme Python convertit le code source en code octet puis l'exécute, il ne contient pas le code source pendant l'exécution. doit. Que se passe-t-il. En fait, Python lit à nouveau le code source après une erreur d'exécution et obtient le code dans cette partie. Pour confirmer cela, j'ai créé hello2.py en ajoutant une ligne au-dessus de hello.py.

hello2.py


input("Please input> ")
print(1/0)

Attend une entrée à «entrée» avant que la division par zéro ne soit effectuée. Pendant ce temps, je vais essayer de réécrire le code source de hello2.py lui-même avec un éditeur. Commencez par démarrer l'exécution et attendez l'entrée.

$ python3 hello2.py 
Please input> 

Réécrivez la deuxième ligne avec le texte approprié.

hello2.py (après réécriture)


input("Please input> ")
Êtes-vous somnolent?

Donnez une contribution appropriée au processus en attendant l'entrée et poursuivez le processus.

$ python3 hello2.py 
Please input> 123[Enter]
Traceback (most recent call last):
  File "hello2.py", line 2, in <module>
Êtes-vous somnolent?
ZeroDivisionError: division by zero

L'erreur de division zéro qui aurait dû se produire avec le code print (1/0), mais Traceback a affiché le texte réécrit, "Êtes-vous somnolent?" Vous pouvez voir que le code source a été chargé après l'erreur.

S'il n'y a pas de fichier source, le code de la partie d'erreur ne sera pas affiché

Mais que se passe-t-il si une erreur se produit lors de l'entrée standard ou de l'exécution d'une chaîne? Le code n'est pas enregistré dans un fichier, il n'y a donc rien à lire après l'erreur. Donnons à Python le hello.py comme entrée standard.

$ python3 < hello.py
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero

Il s'agit de la première ligne de «», mais le code d'erreur réel n'est pas affiché. Alors que faire si vous donnez le code comme argument de ligne de commande?

$ python3 -c 'print(1/0)'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ZeroDivisionError: division by zero

De même, il s'agit de la première ligne de ` '', mais le code de l'erreur n'est pas affiché. Que ce soit «» ou «», le code source ne peut pas être obtenu car ce n'est pas un fichier qui existe réellement.

Que sont «» et «»?

Dans le Traceback ci-dessus, il y avait des indications telles que File" <stdin> " et File" <string> ". Qu'est-ce que c'est? Dans documentation de la fonction de compilation,

filename L'argument doit donner le fichier à partir duquel le code est lu; passer une valeur reconnaissable à moins qu'elle ne soit lue à partir du fichier (`` '' est couramment utilisé. Masu).

Il y a. S'il n'y a pas de fichier source, la chaîne de caractères indiquant l'origine du code source est définie comme "nom de fichier". Si Python rencontre une erreur lors de l'exécution du bytecode, il fera confiance au "nom de fichier" spécifié ici pour créer un Traceback. Étant donné que les fichiers tels que «» et «» n'existent pas, dans ces cas, le code indiquant l'emplacement de l'erreur ne peut pas être obtenu et rien n'y est affiché.

Et s'il y a un fichier qui ne devrait pas être là?

Mais n'y a-t-il absolument aucun fichier comme «» ou «»? Et s'il y en avait? Ces fichiers sont préparés dans un certain répertoire sur une certaine machine introduite au début.

$ ls
<stdin>  <string>
$ cat '<stdin>'
Dois-je me coucher bientôt?
$ cat '<string>'
C'est déjà la limite, non?

Puisque l'entrée en mode interactif de Python se fait à partir de l'entrée standard, le "nom de fichier" défini dans le code d'octet est <stdin>.

>>> eval("1/0")

De plus, le code appelle la fonction ʻeval`, qui compile la chaîne en bytecode. Le "nom de fichier" de ce code d'octet est «<chaîne>». Lorsqu'une erreur se produit, Python approuve ces "noms de fichiers" et crée un Traceback, de sorte que la première ligne de chaque fichier préparé s'affiche.

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
Dois-je me coucher bientôt?
  File "<string>", line 1, in <module>
C'est déjà la limite, non?
ZeroDivisionError: division by zero

C'est la cause du phénomène étrange. À ce stade, le fichier source semble être recherché à partir de sys.path, donc<stdin>et < Cela se produit si string> ʻest dans un répertoire contenu dans sys.path`.

référence

Il y avait un étrange message d'erreur introduit sur Twitter. Pour le code d'octet, reportez-vous à la documentation du module dis.

Recommended Posts

Etrange message d'erreur Python —— Ce code est-il vraiment exécuté?
[Python] tkinter Code susceptible d'être réutilisé
[Python] pandas Code susceptible d'être réutilisé
Ce code Python n'a pas de classes ...
Erreur python d'aujourd'hui: l'image est vide
Code Python qui complète les séquences d'ADN Quelle méthode est la plus rapide?
Erreur d'importation même si Python est installé
Code Python qui supprime les espaces contigus en un