Can a line of Python code know its indentation nesting level?
<p>From something like this:</p>

<pre><code>print(get_indentation_level())

    print(get_indentation_level())

        print(get_indentation_level())
</code></pre>

<p>I would like to get something like this:</p>

<pre><code>1
2
3
</code></pre>

<p>Can the code read itself in this way?</p>

<p>All I want is the output from the more nested parts of the code to be more nested. In the same way that this makes code easier to read, it would make the output easier to read. </p>

<p>Of course I could implement this manually, using e.g. <code>.format()</code>, but what I had in mind was a custom print function which would <code>print(i*' ' + string)</code> where <code>i</code> is the indentation level. This would be a quick way to make readable output on my terminal. </p>

<p>Is there a better way to do this which avoids painstaking manual formatting?</p>

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

<pre><code>if True:
    print(
get_nesting_level())
</code></pre>

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

<pre><code>print(1,
      2,
      get_nesting_level())
</code></pre>

<p>the call to <code>get_nesting_level</code> is nested zero levels deep, despite the presence of leading whitespace on its line.</p>

<p>In the following code:</p>

<pre><code>if True:
  if True:
    print(get_nesting_level())

if True:
    print(get_nesting_level())
</code></pre>

<p>the two calls to <code>get_nesting_level</code> are at different nesting levels, despite the fact that the leading whitespace is identical.</p>

<p>In the following code:</p>

<pre><code>if True: print(get_nesting_level())
</code></pre>

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

<hr>

<p>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 <code>INDENT</code> and <code>DEDENT</code> tokens. The <a href="https://docs.python.org/2/library/tokenize.html"><code>tokenize</code></a> module would be very useful for such a function:</p>

<pre><code>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 &gt; caller_lineno:
                break
            elif token_type == tokenize.INDENT:
                indentation_level += 1
            elif token_type == tokenize.DEDENT:
                indentation_level -= 1
        return indentation_level
</code></pre>

python reflection metaprogramming indentation tokenize