一行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