Как обнаружить ввод / вывод в исходном коде Python (стандартный способ ввода / вывода в библиотеке) - PullRequest
2 голосов
/ 15 февраля 2011

Я строю оптимизирующий компилятор для небольшого подмножества кода на Python для моего проекта в последний год.Первое, что я делаю, это проверяю, участвует или нет переменная в вводе-выводе.Если бы я должен был статически отследить вызов функции по пресловутой кроличьей норе, как бы я узнал, что это связано с вводом / выводом?Будет ли вызов встроенной функции Python, такой как вызовы функции print, input или встроенной функции file, для чтения и записи?

У меня не так много времени, чтобы заняться этим проектом (всего 6 месяцев), поэтому я полностью игнорирую людей, пишущих ввод-вывод на C, оборачивая его каким-то объектом python и вызывая его из python.

Показывает ли сгенерированный байт-код наличие ввода-вывода?Или это бесполезно, как AST?

Не важно, если это невозможно отменить, я просто подмножество ввода / вывода для моего проекта для печати, ввода для чтения и записи.То или делай анализ живучести.

Спасибо.

1 Ответ

2 голосов
/ 15 февраля 2011

Это не так просто, как просто смотреть на байт-код, потому что вызовы вещей - это просто поиск символов:

>>> 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 на своем пути.

...