Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/300.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
一行Python代码可以知道它的缩进嵌套级别吗?_Python_Reflection_Metaprogramming_Indentation_Tokenize - Fatal编程技术网

一行Python代码可以知道它的缩进嵌套级别吗?

一行Python代码可以知道它的缩进嵌套级别吗?,python,reflection,metaprogramming,indentation,tokenize,Python,Reflection,Metaprogramming,Indentation,Tokenize,从这样的东西: print(get_indentation_level()) print(get_indentation_level()) print(get_indentation_level()) 1 2 3 我想得到这样的东西: print(get_indentation_level()) print(get_indentation_level()) print(get_indentation_level()) 1 2 3 代

从这样的东西:

print(get_indentation_level())

    print(get_indentation_level())

        print(get_indentation_level())
1
2
3
我想得到这样的东西:

print(get_indentation_level())

    print(get_indentation_level())

        print(get_indentation_level())
1
2
3
代码能以这种方式读取自身吗

我只希望代码中嵌套较多的部分的输出更加嵌套。与使代码更易于阅读一样,它也会使输出更易于阅读

当然,我可以手动实现,例如使用
.format()
,但我想到的是一个自定义打印函数,它将
打印(I*''+字符串)
,其中
I
是缩进级别。这将是在我的终端上生成可读输出的一种快速方法


有没有更好的方法可以避免费力的手动格式化?

您可以使用
sys.current\u frame.f\u lineno
来获取行号。然后,为了找到缩进级别的编号,您需要找到缩进为零的前一行,然后从该行的编号中减去当前行号,您将得到缩进的编号:

>>> import inspect
>>> help(inspect.indentsize)
Help on function indentsize in module inspect:

indentsize(line)
    Return the indent size, in spaces, at the start of a line of text.
import sys
current_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
演示:

如果您想使用
根据前面几行获得缩进级别的编号,只需稍作更改即可:

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(':'))
演示:

作为替代答案,这里有一个获取缩进数(空格)的函数:


是的,这绝对是可能的,这里有一个有效的例子:

import inspect

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

如果您希望按嵌套级别而不是空格和制表符进行缩进,那么事情会变得棘手。例如,在以下代码中:

if True:
    print(
get_nesting_level())
print(1,
      2,
      get_nesting_level())
if True:
  if True:
    print(get_nesting_level())

if True:
    print(get_nesting_level())
if True: print(get_nesting_level())
get_nesting_level
的调用实际上嵌套了一层,尽管
get_nesting_level
调用的行中没有前导空格。同时,在以下代码中:

if True:
    print(
get_nesting_level())
print(1,
      2,
      get_nesting_level())
if True:
  if True:
    print(get_nesting_level())

if True:
    print(get_nesting_level())
if True: print(get_nesting_level())
get_nesting_level
的调用嵌套为零层深,尽管其行中存在前导空格

在以下代码中:

if True:
    print(
get_nesting_level())
print(1,
      2,
      get_nesting_level())
if True:
  if True:
    print(get_nesting_level())

if True:
    print(get_nesting_level())
if True: print(get_nesting_level())
get_nesting_level
的两个调用处于不同的嵌套级别,尽管前导空格是相同的

在以下代码中:

if True:
    print(
get_nesting_level())
print(1,
      2,
      get_nesting_level())
if True:
  if True:
    print(get_nesting_level())

if True:
    print(get_nesting_level())
if True: print(get_nesting_level())
那是嵌套的零级还是一级?就形式语法中的
INDENT
DEDENT
标记而言,其深度为零级,但您可能不会有相同的感觉


如果要执行此操作,您必须将整个文件标记化到调用点,并计数
INDENT
DEDENT
标记。该模块对于此类功能非常有用:

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

为了解决导致您的问题的“真正”问题,您可以实现一个contextmanager,它跟踪缩进级别,并使代码中带有块结构的
与输出的缩进级别相对应。这样,代码缩进仍然会反映输出缩进,而不会过度耦合两者。仍然可以将代码重构为不同的函数,并根据代码结构生成其他缩进,而不影响输出缩进

#!/usr/bin/env python
# coding: utf8
from __future__ import absolute_import, division, print_function


class IndentedPrinter(object):

    def __init__(self, level=0, indent_with='  '):
        self.level = level
        self.indent_with = indent_with

    def __enter__(self):
        self.level += 1
        return self

    def __exit__(self, *_args):
        self.level -= 1

    def print(self, arg='', *args, **kwargs):
        print(self.indent_with * self.level + str(arg), *args, **kwargs)


def main():
    indented = IndentedPrinter()
    indented.print(indented.level)
    with indented:
        indented.print(indented.level)
        with indented:
            indented.print('Hallo', indented.level)
            with indented:
                indented.print(indented.level)
            indented.print('and back one level', indented.level)


if __name__ == '__main__':
    main()
输出:

0
  1
    Hallo 2
      3
    and back one level 2


我真的很好奇你为什么需要这个。@Harrison我想根据代码中缩进的方式缩进代码的输出。真正的问题是:你为什么需要这个?压痕水平是静态的;当您将
get\u indentation\u level()
station放入代码中时,您肯定知道这一点。您也可以直接执行
打印(3)
或其他任何操作。更重要的是测试函数调用堆栈上嵌套的当前级别。它是为了调试代码吗?这似乎要么是记录执行流程的超级天才方法,要么是针对一个简单问题的超级过度设计的解决方案,我不确定它是哪一种。。。也许两者都有@FabvonBellingshausen:听起来它的可读性比你希望的要差得多。我认为如果显式地传递
depth
参数,并在将其传递给其他函数时根据需要向其添加适当的值,可能会更好。代码的嵌套不太可能与您希望输出的缩进完全对应。这将以空格而不是级别给出缩进。除非程序员使用一致的缩进量,否则将其转换为级别可能很难。函数是否未记录?我找不到与@Prune的注释相关的内容,是否可以将其设置为以级别而不是空格返回缩进?简单地除以4是否总是可以的?不,除以4以获得缩进级别不适用于此代码。可以通过增加上一次打印语句的缩进级别来验证,上一次打印的值只是增加了。这是一个好的开始,但并不能真正回答imo的问题。空格的数量与缩进级别不同。这并不是那么简单。用单个空格替换4个空格可以改变代码的逻辑。但是这段代码非常适合OP所需要的:(OP注释#9):“我想根据代码中缩进的方式缩进代码的输出。”因此他可以执行类似于
打印的操作(“{Space}”*get_indentation_level(),x)
询问的问题是缩进级别的数量,而不是空格的数量。它们不一定是成比例的。对于演示代码,输出应该是1-2-3-3@CraigBurgler为了得到1-2-3-3,我们可以计算当前行之前以
结尾的行数,直到遇到缩进为零的行,请查看编辑!六羟甲基三聚氰胺六甲醚。。。好啊现在试试@user2357112的一些测试用例;)@CraigBurgler这个解决方案只适用于大多数情况,关于这个答案,它也是一个通用的方法,它也没有给出一个全面的解决方案。请尝试
{3:4,\n 2:get\u ind\u num()}
当在该函数调用中调用
get\u nesting\u level()
时,这不会以我期望的方式工作―它返回该函数中的嵌套级别。它能被重写以返回“全局”嵌套级别吗?@FabvonBelling