<질문>
다음과 같이 :
print(get_indentation_level())
print(get_indentation_level())
print(get_indentation_level())
다음과 같은 것을 얻고 싶습니다.
1
2
3
이런 식으로 코드 자체를 읽을 수 있습니까?
내가 원하는 것은 코드의 더 많은 중첩 부분의 출력이 더 중첩되는 것입니다. 이렇게하면 코드를 더 쉽게 읽을 수있는 것과 마찬가지로 출력을 더 쉽게 읽을 수 있습니다.
물론 예를 사용하여 수동으로 구현할 수 있습니다..format()
,하지만 제가 염두에 둔 것은 사용자 정의 인쇄 기능이었습니다.print(i*' ' + string)
어디i
들여 쓰기 수준입니다. 이것은 터미널에서 읽을 수있는 출력을 만드는 빠른 방법입니다.
힘든 수동 서식 지정을 피하는 더 좋은 방법이 있습니까?
<답변1>
공백과 탭이 아닌 중첩 수준 측면에서 들여 쓰기를 원하는 경우 작업이 까다로워집니다. 예를 들어, 다음 코드에서 :
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
형식적인 문법에서 토큰은 0 레벨 깊이이지만 같은 느낌이 들지 않을 수도 있습니다.
이렇게하려면 호출 시점까지 전체 파일을 토큰 화하고 계산해야합니다.INDENT
과DEDENT
토큰. 그만큼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
<답변2>
네, 확실히 가능합니다. 여기에 실제적인 예가 있습니다.
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()
<답변3>
당신이 사용할 수있는sys.current_frame.f_lineno
줄 번호를 얻으려면. 그런 다음 들여 쓰기 수준의 수를 찾으려면 들여 쓰기가 0 인 이전 줄을 찾은 다음 해당 줄의 번호에서 현재 줄 번호를 빼야합니다. 들여 쓰기 수를 얻습니다.
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]))
<답변4>
질문으로 이어지는 "실제"문제를 해결하기 위해 들여 쓰기 수준을 추적하고 확인하는 컨텍스트 관리자를 구현할 수 있습니다.with
코드의 블록 구조는 출력의 들여 쓰기 수준에 해당합니다. 이런 식으로 코드 들여 쓰기는 둘 다 너무 많이 결합하지 않고도 출력 들여 쓰기를 반영합니다. 코드를 다른 함수로 리팩터링하고 출력 들여 쓰기를 엉망으로 만들지 않는 코드 구조를 기반으로 다른 들여 쓰기를하는 것은 여전히 가능합니다.
#!/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
<답변5>
>>> 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.
'개발 > Python' 카테고리의 다른 글
[파이썬] Pandas DataFrame에 tsv 파일을로드하는 방법은 무엇입니까? (0) | 2021.01.21 |
---|---|
파이썬 Django의 그룹에 사용자 추가 (0) | 2021.01.21 |
파이썬에 내장 식별 기능이 있습니까? (0) | 2021.01.21 |
Python에서 내 모듈을 가져올 수 없습니다. (0) | 2021.01.21 |