Это довольно глупая вещь, и большинство людей сказали бы, что это невозможно, (THC4k дает убедительные доказательства этого для общего корпуса), но это звучит забавно и должно быть вполне выполнимо во многих реальных целях.случаи.
шаг 1 .Вы должны сделать шаг назад через кадры.Получите первый с sys._getframe
или inspect.currentframe
(не говорите никому, второй кажется псевдонимом первого).Затем вы можете перебирать их с помощью f.f_back
шаг 2 .У каждого будет инструкция f.f_lasti
.Это последняя инструкция, которая была выполнена в кадре.Вы должны будете сохранить это.Теперь вернитесь назад через байт-код - f.f_code.co_code
- и найдите код операции SETUP_EXCEPT
с аргументом, который переходит на после f.f_lasti`.Точкой перехода является обработка исключений.
шаг 3 .Это где это становится нечетким.Ключ в том, что фактической операцией сравнения будет COMPARE_OP
с 10 в качестве аргумента.Во всех случаях, которые я видел, за этим следует POP_JUMP_IF_FALSE
.Это перейдет к следующему предложению except
или предложению finally
.Ему будет предшествовать код, который загружает загружаемые исключения в стек.Если есть только один, то это будет прямой LOAD_GLOBAL
или LOAD_GLOBAL
или LOAD_FAST
(в зависимости от того, является ли модуль с исключениями глобальным или локальным), за которым следует LOAD_ATTR
.Если сопоставляются несколько исключений, то будет последовательность операций загрузки, за которыми следует BUILD_TUPLE
(идиоматический) или BUILD_LIST
(некоторая другая странная или неидиоматическая ситуация).
Дело в том, чтоВы можете выполнить инструкции LOAD_X
и сравнить имя с соответствующим исключением.Обратите внимание, что вы сравниваете только имя .Если они переназначили имя, вы SOL.
шаг 4 .Давайте предположим, что вы нашли совпадение.Теперь вам нужен объект функции.Лучший способ сделать это следующим образом (я оставляю за собой право на обновление): f.f_code
будет иметь атрибут co_filename
.Вы можете перебрать sys.modules
, и у каждого будет атрибут __name__
.Вы можете сравнить два, имея в виду, что вы должны использовать __name__.endswith(co_filename)
.Когда вы получите совпадение, вы можете зациклить функции модулей и сравнить их атрибут f.func_code.co_firstlineno
с атрибутом frames f.f_lineno
.Когда вы получаете совпадение, у вас есть ваша функция.Вы должны также пройтись по методам каждого класса в модуле.Существует вероятность того, что обработка происходит в какой-то вложенной функции, и в этом случае я не могу сейчас придумать разумную вещь, которую нужно сделать.(Это был бы совершенно другой взлом байт-кода и сам по себе был бы ненадежным)
step 5 .Прибыль.
Это должно дать вам общее представление о том, как это сделать.Существуют всевозможные угловые случаи, когда вы не сможете это сделать, но в любом обычном случае вы должны быть в состоянии осуществить это.Если вы напишите код, который зависит от того, сможете ли вы это сделать, то все равно сломается .Это что-то вроде «Делай, потому что я могу».