#python #monkeypatchin& #inspect
#python #Исправление обезьян #Осмотр
Вопрос:
Я когда-нибудь хотел бы применить небольшие исправления к небольшим проблемам, просто для тестирования или для внутренних целей.
Например, я хотел бы просто заменить self.builder.current_docname
на node.source
в sphinx.writers.html5.HTML5Translator.visit_literal_block
.
(Элегантный) способ сделать это — скопировать-вставить метод, к которому должен быть применен патч, затем изменить маленькую деталь, которую я должен изменить, затем переопределить исходный метод новым. В этом случае у меня было бы много импорта, и мне пришлось бы копировать / вставлять весь метод локально (плохой SSOT — это плохо).
Вместо этого я бы хотел написать что-то вроде:
from monkey import ReMonkeyPatcher # Fake...
from sphinx.writer.html5 import HTML5Translator
# Override the class's method
ReMonkeyPatcher(HTML5Translator, 'self.builder.current_docname', 'node.source')
# Profit...
Здесь я читал, что отражающая природа Python допускает взломы во время выполнения с помощью inspect
и ast
. Итак, я написал это:
def monkey_replace(function, search, replace):
source = inspect.&etsource(function)
while code[0].isspace():
code = textwrap.dedent(code)
code = code.replace(search, replace)
ast_tree = ast.parse(code)
compile(ast_tree, '<strin&&&t;', mode='exec')
mod = {}
exec(code, mod) # <-- Here is the issue...
method = mod[function.__name__]
replace_function(function, method) # Doesn't know how to do that yet
Основная проблема заключается в том, exec(code, mod)
что контекст отсутствует. Чтобы работать в любом / большинстве случаев, оно должно выполняться в контексте исходной функции (импортирует …).
Есть ли элегантный способ сделать это?
Комментарии:
1. Опоздание на вечеринку на год, но &ithub.com/adamchainz/patchy возможно, это то, что вы ищете!
Ответ №1:
В Python monkey-исправление чрезвычайно просто. Как сказано в сообщении, на которое вы ссылаетесь: поскольку защищенных переменных нет, вы можете просто перезаписать функцию, которую вы хотели бы исправить:
HTMLTranslator.builder.current_docname = node.source
Комментарии:
1. почему вы отклонили это? можете ли вы добавить комментарий со своей критикой?