Быстрый ответ
Возможно ли динамическое добавление атрибутов к встроенным объектам Python в Python?
Нет, причины, по которым вы читаете ссылки, которые вы опубликовали, совпадают сейчас дни.Но я вышел с рецептом, который, как мне кажется, может стать отправной точкой вашего трейсера.
Инструментарий с использованием подклассов в сочетании с AST
После прочтения этого я получил рецепт, которыйможет быть не полным решением, но похоже, что вы можете начать отсюда.
Хорошая особенность этого рецепта в том, что он не использует сторонние библиотеки, все достигается с помощью стандарта (Python3.5, 3.6, 3.7) библиотеки.
Целевой код.
Этот рецепт заставит код, подобный этому, быть инструментирован (здесь выполняется простая инструментарий, это всего лишь идея концепции) и выполнен.
# target/target.py
d = {1: 2}
d.update({3: 4})
print(d) # Should print "{1: 2, 3: 4}"
print(d.hidden_field) # Should print "(0, 0)"
Подклассы
Сначала нужно добавить hidden_field
ко всему, что мы хотим (этот рецепт был проверен только со словарями).
СледующееКод получает значение, узнает его тип / класс и подкласс его, чтобы добавить упомянутые hidden_field
.
def instrument_node(value):
VarType = type(value)
class AnalyserHelper(VarType):
def __init__(self, *args, **kwargs):
self.hidden_field = (0, 0)
super(AnalyserHelper, self).__init__(*args, **kwargs)
return AnalyserHelper(value)
с тем, что вы можете:
d = {1: 2}
d = instrument_node(d)
d.update({3: 4})
print(d) # Do print "{1: 2, 3: 4}"
print(d.hidden_field) # Do print "(0, 0)"
В к этому моменту мы уже знаем способ «добавить инструментарий во встроенный словарь» , но здесь нет прозрачности .
Изменить AST.
Следующим шагом будет «скрыть» вызов instrument_node
, и мы сделаем это с помощью модуля ast Python.
Ниже приведен преобразователь узла AST, который будет приниматьлюбой найденный словарь и оберните его в instrument_node
вызов:
class AnalyserNodeTransformer(ast.NodeTransformer):
"""Wraps all dicts in a call to instrument_node()"""
def visit_Dict(self, node):
return ast.Call(func=ast.Name(id='instrument_node', ctx=ast.Load()),
args=[node], keywords=[])
return node
Соберите все вместе.
С помощью этих инструментов вы можете написать скрипт, который:
- Считать целевой код.
- Разобрать программу.
- Применить изменения AST.
- Скомпилируйте его.
- И выполните его.
import ast
import os
from ast_transformer import AnalyserNodeTransformer
# instrument_node need to be in the namespace here.
from ast_transformer import instrument_node
if __name__ == "__main__":
target_path = os.path.join(os.path.dirname(__file__), 'target/target.py')
with open(target_path, 'r') as program:
# Read and parse the target script.
tree = ast.parse(program.read())
# Make transformations.
tree = AnalyserNodeTransformer().visit(tree)
# Fix locations.
ast.fix_missing_locations(tree)
# Compile and execute.
compiled = compile(tree, filename='target.py', mode='exec')
exec(compiled)
Это займет наш целевой код и обернет каждый словарь instrument_node()
и выполнить результат такого изменения.
Результат выполнения этого с нашим целевым кодом,
# target/target.py
d = {1: 2}
d.update({3: 4})
print(d) # Will print "{1: 2, 3: 4}"
print(d.hidden_field) # Will print "(0, 0)"
:
>>> {1: 2, 3: 4}
>>> (0, 0)
Рабочий пример
Вы можете клонировать рабочий пример здесь .