2016-07-13 2 views
0

Можно ли определить уровень отступов строки на Python во время работы программы? Я хочу, чтобы иметь возможность организовать файл журнала в соответствии с структурой структуры выполняемого сценария.Определить уровень отступа строки в настоящее время Python Code

В следующем примере, функция «первое сообщение» даст 0, «второе сообщение» будет 1, «третье сообщение» 2 и «четвертый, пятый, шестой» сообщение будет 0

logger.debug('First message') 
if True: 
    logger.info('Second message') 
    if True: 
     logger.info('Third message') 


logger.warning('Fourth message') 
logger.error('Fifth message') 
logger.critical('Sixth message') 

соответствующий файл журнала будет выглядеть примерно так:

First message 
    Second message 
     Third message 
Fourth message 
Fifth message 
Sixth message 
+0

Вы можете посмотреть прилагаемый фрейм: http://stackoverflow.com/q/5326539/3001761, но это похоже на большую работу, для небольшой выгоды. – jonrsharpe

+0

@ jonrsharpe - Причина, по которой требуется просить об этом, состоит в том, чтобы иметь схему тестового примера, чтобы можно было увидеть скелет о том, почему произошел сбой, без необходимости просканировать исходный код теста. Различные уровни отступов делают его более легким для чтения. – packersfan16

ответ

0

я был в состоянии определить уровень отступа с помощью inspect.getouterframes функции(). Это предполагает, что вместо '\ t' символов для отступов используются 4 '' символы.

import inspect 

def getIndentationLevel():  

    # get information about the previous stack frame 
    frame, filename, line_number,function_name, lines, index = inspect.getouterframes(inspect.currentframe())[1] 

    # count the number of characters in the line 
    original_length = len(lines[0]) 

    # trim the line of left spaces and record the new length 
    new_length = len(lines[0].lstrip()) 

    # take the difference between the two values and divide by 4 to get the level number 
    return int((original_length - new_length)/4) 
0

Во-первых, я получить контекст кода вызывающего абонента:

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() 

Я бы не решался использовать это в производственном коде. Использование проверки кода подобно этому хрупкое, и в зависимости от того, где вы это называете, это может привести к неожиданным последствиям.

+1

Можете ли вы указать какой-либо контекст/пояснение вашего примера кода? – mhatch

+0

Конечно, я добавил комментарий. – Jan

Смежные вопросы