Вы можете посмотреть, что запускает виртуальная машина Python, используя dis
:
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.как вы можете видеть из строк с 10 по 24, на самом деле речь идет о печати.
Только когда вы достигнете строки 26, ВМ Python пытается загрузить функцию, что приводит к ошибке имени.
Немного по-разному, когда компилируемый язык выполняет компиляциюДля байт-кода (например, от 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 сможет найти ее.