Programing

파이썬 코드 줄이 들여 쓰기 중첩 수준을 알 수 있습니까?

lottogame 2020. 6. 15. 08:17
반응형

파이썬 코드 줄이 들여 쓰기 중첩 수준을 알 수 있습니까?


이런 식으로 :

print(get_indentation_level())

    print(get_indentation_level())

        print(get_indentation_level())

나는 이와 같은 것을 얻고 싶다 :

1
2
3

이 방법으로 코드를 읽을 수 있습니까?

내가 원하는 것은 코드의 더 중첩 된 부분의 출력이 더 중첩 될 것입니다. 이렇게하면 코드를보다 쉽게 ​​읽을 수 있으며 출력을보다 쉽게 ​​읽을 수 있습니다.

물론 나는 이것을 사용하여 수동으로 이것을 구현할 수 .format()있었지만, 내가 염두에 두었던 것은 들여 쓰기 수준 print(i*' ' + string)어디에 있는 사용자 정의 인쇄 기능이었습니다 i. 이것은 내 터미널에서 읽을 수있는 출력을 만드는 빠른 방법입니다.

번거로운 수동 서식을 피하는 더 좋은 방법이 있습니까?


공백과 탭이 아닌 중첩 수준으로 들여 쓰기를 원하면 까다로워집니다. 예를 들어 다음 코드에서

if True:
    print(
get_nesting_level())

호출 get_nesting_level라인에 선행 공백이 없다는 사실에도 불구하고 호출 은 실제로 한 레벨 깊이 중첩 get_nesting_level됩니다. 한편, 다음 코드에서 :

print(1,
      2,
      get_nesting_level())

get_nesting_level행에 선행 공백이 있음에도 불구하고 호출 은 0 레벨 깊이에 중첩됩니다.

다음 코드에서

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

if True:
    print(get_nesting_level())

get_nesting_level선행 공백이 동일하다는 사실에도 불구하고 두 호출 은 서로 다른 중첩 수준에 있습니다.

다음 코드에서

if True: print(get_nesting_level())

중첩 된 0 수준입니까, 아니면 1입니까? 의 측면에서 INDENT그리고 DEDENT형식적인 문법 토큰, 그것은 깊은 제로 수준입니다,하지만 당신은 같은 생각하지 않을 수 있습니다.


이 작업을 수행하려면 전체 파일을 호출 시점 및 카운트 INDENTDEDENT토큰까지 토큰 화해야합니다. tokenize모듈은 이러한 기능을 위해 매우 유용 할 것입니다 :

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

예, 확실히 가능합니다. 실제 사례는 다음과 같습니다.

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

sys.current_frame.f_lineno줄 번호를 얻기 위해 사용할 수 있습니다 . 그런 다음 들여 쓰기 수준의 수를 찾으려면 들여 쓰기가없는 이전 줄을 찾은 다음 해당 줄 번호에서 현재 줄 번호를 빼면 들여 쓰기 횟수가 표시됩니다.

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

데모:

if True:
    print get_ind_num()
    if True:
        print(get_ind_num())
        if True:
            print(get_ind_num())
            if True: print(get_ind_num())
# Output
1
3
5
6

이전 줄을 기반으로 들여 쓰기 수준의 수를 원한다면 :약간의 변경만으로 할 수 있습니다.

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

데모:

if True:
    print get_ind_num()
    if True:
        print(get_ind_num())
        if True:
            print(get_ind_num())
            if True: print(get_ind_num())
# Output
1
2
3
3

그리고 대안으로 여기에 들여 쓰기 횟수 (공백)를 얻는 함수가 있습니다.

import sys
from itertools import takewhile
current_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]))

To solve the ”real” problem that lead to your question you could implement a contextmanager which keeps track of the indention level and make the with block structure in the code correspond to the indentation levels of the output. This way the code indentation still reflects the output indentation without coupling both too much. It is still possible to refactor the code into different functions and have other indentations based on code structure not messing with the output indentation.

#!/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()

Output:

0
  1
    Hallo 2
      3
    and back one level 2

>>> 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.

참고URL : https://stackoverflow.com/questions/39172306/can-a-line-of-python-code-know-its-indentation-nesting-level

반응형