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

前端 未结 5 674
失恋的感觉
失恋的感觉 2021-01-30 07:40

From something like this:

print(get_indentation_level())

    print(get_indentation_level())

        print(get_indentation_level())

I would li

5条回答
  •  刺人心
    刺人心 (楼主)
    2021-01-30 08:20

    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 inspect
    import tokenize
    
    def 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
    

提交回复
热议问题