如果在解释/ JITing之前将Python源代码编译为字节码,为什么在运行时之前未捕获到此错误?

时间:2018-11-20 12:10:43

标签: python compilation interpreter

我编写了以下函数:

def f():
    for i in range(100000):
        print(i)
    some_function_that_doesnt_exist()

运行文件时,这将打印出100000范围内的数字,然后引发错误:NameError: name 'some_function_that_doesnt_exist' is not defined

这是一个有关Python的更广泛问题的示例。如果在Python VM解释(或通过JIT对其进行解释)之前将Python代码编译为字节码,为什么在编译过程中没有看到此错误?为什么在最终看到错误之前打印出100000个数字?在像C这样的纯编译语言中,我们会在编译时看到错误,那么为什么我们不能在这种“部分编译”语言中看到它?

2 个答案:

答案 0 :(得分:3)

您可以使用dis查看python VM的运行情况:

import dis

def f():
    for i in range(100000):
        print(i)
    some_function_that_doesnt_exist()


dis.dis(f)

将输出:

  4           0 SETUP_LOOP              24 (to 26)
              2 LOAD_GLOBAL              0 (range)
              4 LOAD_CONST               1 (100000)
              6 CALL_FUNCTION            1
              8 GET_ITER
        >>   10 FOR_ITER                12 (to 24)
             12 STORE_FAST               0 (i)

  5          14 LOAD_GLOBAL              1 (print)
             16 LOAD_FAST                0 (i)
             18 CALL_FUNCTION            1
             20 POP_TOP
             22 JUMP_ABSOLUTE           10
        >>   24 POP_BLOCK

  6     >>   26 LOAD_GLOBAL              2 (some_function_that_doesnt_exist)
             28 CALL_FUNCTION            0
             30 POP_TOP
             32 LOAD_CONST               0 (None)
             34 RETURN_VALUE

这是python VM实际运行的内容。从第10到24行可以看到,它实际上是处理打印的。
仅当到达第26行时,python VM才会尝试加载该函数,这会导致名称错误。



稍有不同,当编译语言将代码编译为字节码(例如,从C到汇编)时,函数调用需要确切知道函数在内存中的位置。因此,当您尝试编译不存在的函数时,它将无法将其转换为字节码,因为它将无法查找函数位置。
Python VM可以访问可以实时修改的全局数组,并且在该数组中的查找也是实时的。
正在执行:

dis.dis("def some_function_that_doesnt_exist(): 1")

将导致:

  1           0 LOAD_CONST               0 (<code object some_function_that_doesnt_exist at 0x7f38dc90ed20, file "<dis>", line 1>)
              2 LOAD_CONST               1 ('some_function_that_doesnt_exist')
              4 MAKE_FUNCTION            0
              6 STORE_NAME               0 (some_function_that_doesnt_exist)
              8 LOAD_CONST               2 (None)
             10 RETURN_VALUE

第2行从const表中加载函数名称,然后在第4行创建函数后,根据名称在第6行存储它。因此,当下次查找该函数时,python VM将能够找到它。

答案 1 :(得分:1)

Python代码被编译为字节码,然后在运行时解释该字节码。您的代码是完全有效的Python,因此它将成功编译为字节码。但是,当解释程序尝试执行该字节码时,它将在运行时引发错误。