Can a line of Python code know its indentation nesting level? Can a line of Python code know its indentation nesting level? python python

Can a line of Python code know its indentation nesting level?


If you want indentation in terms of nesting level rather than spaces and tabs, things get tricky. For example, in the following code:

if True:    print(get_nesting_level())

the call to get_nesting_level is actually nested one level deep, despite the fact that there is no leading whitespace on the line of the get_nesting_level call. Meanwhile, in the following code:

print(1,      2,      get_nesting_level())

the call to get_nesting_level is nested zero levels deep, despite the presence of leading whitespace on its line.

In the following code:

if True:  if True:    print(get_nesting_level())if True:    print(get_nesting_level())

the two calls to get_nesting_level are at different nesting levels, despite the fact that the leading whitespace is identical.

In the following code:

if True: print(get_nesting_level())

is that nested zero levels, or one? In terms of INDENT and DEDENT tokens in the formal grammar, it's zero levels deep, but you might not feel the same way.


If you want to do this, you're going to have to tokenize the whole file up to the point of the call and count INDENT and DEDENT tokens. The tokenize module would be very useful for such a function:

import inspectimport tokenizedef get_nesting_level():    caller_frame = inspect.currentframe().f_back    filename, caller_lineno, _, _, _ = inspect.getframeinfo(caller_frame)    with open(filename) as f:        indentation_level = 0        for token_record in tokenize.generate_tokens(f.readline):            token_type, _, (token_lineno, _), _, _ = token_record            if token_lineno > caller_lineno:                break            elif token_type == tokenize.INDENT:                indentation_level += 1            elif token_type == tokenize.DEDENT:                indentation_level -= 1        return indentation_level


Yeah, that's definitely possible, here's a working example:

import inspectdef get_indentation_level():    callerframerecord = inspect.stack()[1]    frame = callerframerecord[0]    info = inspect.getframeinfo(frame)    cc = info.code_context[0]    return len(cc) - len(cc.lstrip())if 1:    print get_indentation_level()    if 1:        print get_indentation_level()        if 1:            print get_indentation_level()


You can use sys.current_frame.f_lineno in order to get the line number. Then in order to find the number of indentation level you need to find the previous line with zero indentation then be subtracting the current line number from that line's number you'll get the number of indentation:

import syscurrent_frame = sys._getframe(0)def get_ind_num():    with open(__file__) as f:        lines = f.readlines()    current_line_no = current_frame.f_lineno    to_current = lines[:current_line_no]    previous_zoro_ind = len(to_current) - next(i for i, line in enumerate(to_current[::-1]) if not line[0].isspace())    return current_line_no - previous_zoro_ind

Demo:

if True:    print get_ind_num()    if True:        print(get_ind_num())        if True:            print(get_ind_num())            if True: print(get_ind_num())# Output1356

If you want the number of the indentation level based on the previouse lines with : you can just do it with a little change:

def get_ind_num():    with open(__file__) as f:        lines = f.readlines()    current_line_no = current_frame.f_lineno    to_current = lines[:current_line_no]    previous_zoro_ind = len(to_current) - next(i for i, line in enumerate(to_current[::-1]) if not line[0].isspace())    return sum(1 for line in lines[previous_zoro_ind-1:current_line_no] if line.strip().endswith(':'))

Demo:

if True:    print get_ind_num()    if True:        print(get_ind_num())        if True:            print(get_ind_num())            if True: print(get_ind_num())# Output1233

And as an alternative answer here is a function for getting the number of indentation (whitespace):

import sysfrom itertools import takewhilecurrent_frame = sys._getframe(0)def get_ind_num():    with open(__file__) as f:        lines = f.readlines()    return sum(1 for _ in takewhile(str.isspace, lines[current_frame.f_lineno - 1]))