Это не так просто, как просто смотреть на байт-код, потому что вызовы вещей - это просто поиск символов:
>>> def write_to_a_file(s):
f = open('foo.txt', 'w')
f.write(s)
f.close()
>>> import dis
>>> dis.dis(write_to_a_file)
2 0 LOAD_GLOBAL 0 (open)
3 LOAD_CONST 1 ('foo.txt')
6 LOAD_CONST 2 ('w')
9 CALL_FUNCTION 2
12 STORE_FAST 1 (f)
3 15 LOAD_FAST 1 (f)
18 LOAD_ATTR 1 (write)
21 LOAD_FAST 0 (s)
24 CALL_FUNCTION 1
27 POP_TOP
4 28 LOAD_FAST 1 (f)
31 LOAD_ATTR 2 (close)
34 CALL_FUNCTION 0
37 POP_TOP
38 LOAD_CONST 0 (None)
41 RETURN_VALUE
Байт-коды сами по себе просто загружают вещи, вызывают вещи и хранят вещи.На самом деле вам придется посмотреть на полезную нагрузку, если вы работаете на уровне байт-кода.
Проверьте текущий список байт-кодов Python , и вы увидите, что на самом деле ничего такого нетразличает вызовы ввода / вывода.
Даже если бы вы проверяли все вызовы LOAD_GLOBAL
или LOAD_FAST
и применяли белый список, это не обязательно работало бы, потому что есть модули, которые обеспечивают ввод / вывод иБайт-код на самом деле вам тоже не поможет:
>>> def uses_a_module_for_io(s):
import shutil
shutil.copy(s, 'foo.txt')
>>> dis.dis(uses_a_module_for_io)
2 0 LOAD_CONST 1 (-1)
3 LOAD_CONST 0 (None)
6 IMPORT_NAME 0 (shutil)
9 STORE_FAST 1 (shutil)
3 12 LOAD_FAST 1 (shutil)
15 LOAD_ATTR 1 (copy)
18 LOAD_FAST 0 (s)
21 LOAD_CONST 2 ('foo.txt')
24 CALL_FUNCTION 2
27 POP_TOP
28 LOAD_CONST 0 (None)
31 RETURN_VALUE
>>> def doesnt_use_shutil_really(s):
shutil = object()
shutil.copy = lambda x,y: None
shutil.copy(s, 'foo.txt')
>>> dis.dis(doesnt_use_shutil_really)
2 0 LOAD_GLOBAL 0 (object)
3 CALL_FUNCTION 0
6 STORE_FAST 1 (shutil)
3 9 LOAD_CONST 1 (<code object <lambda> at 011D8AD0, file "<pyshell#29>", line 3>)
12 MAKE_FUNCTION 0
15 LOAD_FAST 1 (shutil)
18 STORE_ATTR 1 (copy)
4 21 LOAD_FAST 1 (shutil)
24 LOAD_ATTR 1 (copy)
27 LOAD_FAST 0 (s)
30 LOAD_CONST 2 ('foo.txt')
33 CALL_FUNCTION 2
36 POP_TOP
37 LOAD_CONST 0 (None)
40 RETURN_VALUE
Обратите внимание, что LOAD_FAST
для shutil
может быть чем-то, что пользователь просто придумает.В моем случае я просто сделал его универсальным объектом, но у пользователя может быть и другой shutil
на своем пути.