确定当前运行Python代码的行的缩进级别

时间:2016-07-13 13:15:15

标签: python python-3.x logging indentation

在程序运行时是否可以确定Python中行的缩进级别?我希望能够根据正在运行的脚本的大纲结构来组织日志文件。

在以下示例中,第一条消息'函数会产生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

2 个答案:

答案 0 :(得分:0)

我能够使用inspect.getouterframes()函数确定缩进级别。这假定使用4''字符代替'\ t'字符进行缩进。

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)

答案 1 :(得分: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)

如果我可以简单地用一个装饰器包装现有的记录器,将这个记录器变成一个空白感知的记录器,那就太好了。假设我有一个非常原始的记录器,它只是将消息打印到stdout:

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()
但是,我会犹豫是否在生产代码中使用它。像这样使用代码检查是很脆弱的,并且根据你调用它的位置,它可能会导致意想不到的效果。