Во-первых, я получить контекст кода вызывающего абонента:
import inspect
context = inspect.getframeinfo(frame.f_back).code_context
Это дает мне список строк кода; Я игнорирую все, кроме первой строки. Затем я использую регулярное выражение, чтобы получить пробел в начале этой строки; если вы используете вкладки, вы должны заменить их с соответствующим количеством пробелов первой:
import re
indent = re.compile("^ *")
firstline = context[0]
firstline = firstline.replace("\t", " ")
match = indent.match(firstline)
Для тестирования я заменить пробелы с точками, так что я могу видеть, что происходит, и построить свой префикс:
white = "." * match.span(0)[1] # Change "." to " "!
Теперь я могу использовать это, чтобы изменить мое сообщение msg
я послал в мой регистратор:
do_some_logging(white + msg)
было бы хорошо, если бы я мог просто обернуть существующий регистратор с де corator, который превращает этот регистратор в ведомый журнал. Предположим, что я, для целей тестирования, очень примитивный регистратор, который просто выводит сообщения на стандартный вывод:
def pseudo_logger(msg):
"""Pseudo-logging function."""
print(msg)
Этот регистратор имеет первый параметр для сообщения лесозаготовительной и потенциально некоторые другие позиционные параметры и ключевые слова. Я хочу написать decorater для такой функции:
from functools import wraps
def indented(func):
"""Turns the logger func(msg) into an indented logger."""
@wraps(func)
def wrapped(msg, *args, **kwargs):
# ... compute white ...
func(white + msg, *args, **kwargs)
return wrapped
Теперь я могу получить новый регистратор, как, например:
new_logger = intented(pseudo_logger)
Положив все это вместе дает:
from functools import wraps
import inspect
import re
def indented(func):
"""Turns the logger func(msg) into an indented logger."""
indent = re.compile("^ *")
@wraps(func)
def wrapped(msg, *args, **kwargs):
frame = inspect.currentframe()
context = inspect.getframeinfo(frame.f_back).code_context
firstline = context[0]
match = indent.match(firstline)
white = "." * match.span(0)[1] # Change "." to " "!
func(white + msg, *args, **kwargs)
return wrapped
@indented
def pseudo_logger(msg):
"""Pseudo-logging function."""
print(msg)
def main():
pseudo_logger("This is an indented message!")
if True:
pseudo_logger("Another message, but more indented!")
pseudo_logger("This "
"will ignore the indention of the second "
"or third line.")
if __name__ == "__main__":
main()
Я бы не решался использовать это в производственном коде. Использование проверки кода подобно этому хрупкое, и в зависимости от того, где вы это называете, это может привести к неожиданным последствиям.
Вы можете посмотреть прилагаемый фрейм: http://stackoverflow.com/q/5326539/3001761, но это похоже на большую работу, для небольшой выгоды. – jonrsharpe
@ jonrsharpe - Причина, по которой требуется просить об этом, состоит в том, чтобы иметь схему тестового примера, чтобы можно было увидеть скелет о том, почему произошел сбой, без необходимости просканировать исходный код теста. Различные уровни отступов делают его более легким для чтения. – packersfan16