Простое исправление универсальной обезьяны во время выполнения в Python?

#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. почему вы отклонили это? можете ли вы добавить комментарий со своей критикой?