Weird Python error message ——Is that code really executed?

Strange error message, what's happening?

I typed ʻeval ("1/0") `in interactive Python (CPython) in a directory on a machine.

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>
Should I go to bed soon?
  File "<string>", line 1, in <module>
It ’s already the limit, right?
ZeroDivisionError: division by zero

Well, divide by zero and run-time error, which is as expected. But, "Why don't you go to bed soon?" "It's already the limit." What is this?

Python on this machine hasn't been modified, and so does the standard library. No program was written to cause this phenomenon. What could be the cause?

If there is an error running the source file, the corresponding code will be displayed

Move away from the machine with strange messages and check the nature of Traceback that is displayed when an error occurs. First, try running the source file hello.py, which causes division by zero.

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

Traceback shows that the error occurred on the line print (1/0). This is the expected behavior.

The code of the error part is obtained after the error occurs

As shown above, it is convenient to see the source code that caused the error in Traceback, but since Python converts the source code to bytecode and then executes it, it does not hold the source code during execution. must. What's going on. In fact, Python re-reads the source code after a run-time error to get the code in question. To confirm this, I created hello2.py with a line added on top of hello.py.

hello2.py


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

Waits for input at ʻinputbefore division by zero is done. During this time, I will try to rewrite the source code ofhello2.py` itself with an editor. First, start execution and wait for input.

$ python3 hello2.py 
Please input> 

Rewrite the second line with appropriate text.

hello2.py (after rewriting)


input("Please input> ")
Are you sleepy?

Give appropriate input to the process waiting for input and proceed with the process.

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

It was a division by zero error that should have occurred with the code print (1/0), but Traceback displayed the rewritten text, "Are you sleepy?" You can see that the source code is loaded after the error occurs.

If there is no source file, the code of the error part will not be displayed

But what if you get an error in standard input or string execution? The code is not saved in a file, so there is nothing to read after the error occurs. Let's give Python the hello.py as standard input.

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

It is shown to be the first line of <stdin>, but it does not show the code for the actual error. So what if you give the code as a command line argument?

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

Similarly, it is shown to be the first line of <string>, but the code for the error is not displayed. Whether it's <stdin> or <string>, it doesn't actually exist, so you can't get the source code.

What are <stdin> and <string>?

The Traceback above displayed something like File" <stdin> " or File" <string> ". What is this? In compile function documentation,

filename The argument must give the file from which the code is read; pass a recognizable value unless it is read from the file ('<string>' is commonly used. Masu).

There is. If there is no source file, the character string indicating the origin of the source code is set as the "file name". If Python encounters an error executing bytecode, it will trust the "filename" specified here to create a Traceback. Files such as <stdin> and <string> do not exist, so in these cases the code indicating the error location cannot be obtained and nothing is displayed there.

What if there is a file that shouldn't be there?

But are there absolutely no files like <stdin> or <string>? What if there was? These files are prepared in a certain directory on a certain machine introduced at the beginning.

$ ls
<stdin>  <string>
$ cat '<stdin>'
Should I go to bed soon?
$ cat '<string>'
It ’s already the limit, right?

Since the input to Python's interactive mode is made from standard input, the "filename" set in the bytecode is <stdin>.

>>> eval("1/0")

In addition, that code calls the ʻevalfunction, which compiles the string into bytecode. The "filename" of that bytecode is`. When an error occurs, Python trusts these "filenames" and creates a Traceback, so the first line of each of the prepared files is displayed.

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
Should I go to bed soon?
  File "<string>", line 1, in <module>
It ’s already the limit, right?
ZeroDivisionError: division by zero

This is the cause of the strange phenomenon. At this time, the source file seems to be searched from sys.path, so <stdin> and < This happens if string> is in a directory contained in sys.path.

reference

There was a strange error message introduced on Twitter. For bytecode, refer to dis module documentation.

Recommended Posts

Weird Python error message ——Is that code really executed?
[Python] tkinter Code that is likely to be reused
[Python] pandas Code that is likely to be reused
That Python code has no classes ...
Today's python error: image is blank
Python code that makes DNA sequences complementary strands Which method is faster?
Import error even though python is installed
Python code that removes contiguous spaces into one