파이썬 여러 줄 문자열에 대한 적절한 들여 쓰기


456

함수 내에서 파이썬 여러 줄 문자열에 적절한 들여 쓰기는 무엇입니까?

    def method():
        string = """line one
line two
line three"""

또는

    def method():
        string = """line one
        line two
        line three"""

또는 다른 것?

첫 번째 예제에서 문자열이 함수 외부에 매달려있는 것은 이상하게 보입니다.


4
독 스트링은 특별하게 취급 됩니다 : 첫 줄의 들여 쓰기가 제거됩니다. 공백이 아닌 다른 모든 줄에서 가져온 가장 작은 공통 들여 쓰기가 모두 제거됩니다. 그 외에도 파이썬의 여러 줄 문자열 리터럴은 불행히도 공백으로 볼 수있는 것입니다. 문자열 구분 기호 사이의 모든 문자는 들여 쓰기를 포함하여 문자열의 일부가됩니다. 리터럴이 시작되는 줄의 들여 쓰기에서 측정 해야하는 것처럼 보입니다.
Evgeni Sergeev

@EvgeniSergeev 처리 도구는이 작업을 수행합니다 (대개 선택한 처리 도구에 따라 달라짐). method.__doc__파이썬 자체는 다른 str리터럴 보다 더 많이 수정되지 않습니다 .
cz

답변:


453

당신은 아마 """

def foo():
    string = """line one
             line two
             line three"""

줄 바꿈과 공백은 문자열 자체에 포함되므로이를 사후 처리해야합니다. 그렇게하고 싶지 않고 텍스트가 많으면 텍스트 파일에 별도로 저장하는 것이 좋습니다. 텍스트 파일이 응용 프로그램에서 제대로 작동하지 않고 후 처리를 원하지 않으면 아마도

def foo():
    string = ("this is an "
              "implicitly joined "
              "string")

필요없는 부품을 제거 textwrap하기 위해 여러 줄 문자열을 후 처리하려면 PEP 257에 제시된 모듈 또는 후 처리 문자열을위한 기술을 고려해야합니다 .

def trim(docstring):
    if not docstring:
        return ''
    # Convert tabs to spaces (following the normal Python rules)
    # and split into a list of lines:
    lines = docstring.expandtabs().splitlines()
    # Determine minimum indentation (first line doesn't count):
    indent = sys.maxint
    for line in lines[1:]:
        stripped = line.lstrip()
        if stripped:
            indent = min(indent, len(line) - len(stripped))
    # Remove indentation (first line is special):
    trimmed = [lines[0].strip()]
    if indent < sys.maxint:
        for line in lines[1:]:
            trimmed.append(line[indent:].rstrip())
    # Strip off trailing and leading blank lines:
    while trimmed and not trimmed[-1]:
        trimmed.pop()
    while trimmed and not trimmed[0]:
        trimmed.pop(0)
    # Return a single string:
    return '\n'.join(trimmed)

10
이것은 '매달려 진 들여 쓰기'스타일 연속입니다. 함수 정의 및 long if 문과 같은 목적으로 PEP8에 규정되어 있지만 여러 줄 문자열에 대해서는 언급되지 않았습니다. 개인적으로 이것은 PEP8을 따르기를 거부하는 한 장소이며 대신 들여 쓰기를 싫어하여 프로그램의 올바른 구조를 모호하게합니다.
bobince

2
@buffer, 공식 튜터리얼 3.1.2 ( "서로 옆에있는 두 개의 문자열 리터럴이 자동으로 연결됩니다 ...") 및 언어 참조.
Mike Graham

5
자동 문자열 연결을 사용하는 두 번째 양식에는 줄 바꿈포함되지 않습니다 . 기능입니다.
Mike Graham

18
trim()로 PEP257에 지정된 함수는 다음과 같이 표준 라이브러리에서 구현된다 inspect.cleandoc.

2
당신이에서 변수 이름을 변경하는 경우 특히 때문에 ... 여기에 "매달려 들여 쓰기를"거부에 대한 @bobince에 하나의 의견 string으로 text또는 다른 길이의 아무것도 당신이 지금의 들여 쓰기 업데이트해야, 의 말 그대로 모든 단일 라인 여러 줄 문자열을""" 올바르게 일치시킵니다 . 들여 쓰기 전략해야하지 복잡한 미래 refactors / 유지 보수 및 PEP 정말 실패하는 장소의 그것의 하나
kevlarr

254

textwrap.dedent함수를 사용 하면 source에서 올바른 들여 쓰기 로 시작한 다음 사용하기 전에 텍스트에서 제거 할 수 있습니다.

다른 사람들이 지적했듯이, 이것은 리터럴에 대한 추가 함수 호출이라는 것입니다. 코드에서 이러한 리터럴을 배치 할 위치를 결정할 때이 점을 고려하십시오.

import textwrap

def frobnicate(param):
    """ Frobnicate the scrognate param.

        The Weebly-Ruckford algorithm is employed to frobnicate
        the scrognate to within an inch of its life.

        """
    prepare_the_comfy_chair(param)
    log_message = textwrap.dedent("""\
            Prepare to frobnicate:
            Here it comes...
                Any moment now.
            And: Frobnicate!""")
    weebly(param, log_message)
    ruckford(param)

\로그 메시지 리터럴 의 후행 은 줄 바꿈이 리터럴에 없는지 확인하는 것입니다. 그런 식으로 리터럴은 빈 줄로 시작하지 않고 다음 전체 줄로 시작합니다.

from의 반환 값은 textwrap.dedent문자열의 각 줄에서 모든 공통 선행 공백 들여 쓰기가 제거 된 입력 문자열입니다 . 위의 log_message값은 다음과 같습니다.

Prepare to frobnicate:
Here it comes...
    Any moment now.
And: Frobnicate!

1
이것은 합리적인 해결책이며 알기 쉽지만 자주 호출되는 함수 내에서 이와 같은 작업을 수행하면 재앙이 될 수 있습니다.
haridsv

@haridsv 왜 재앙일까요?
jtmoulia 2016 년

10
@jtmoulia : 재난보다 나은 설명 textwrap.dedent()은 입력 인수와 마찬가지로 호출 결과 가 일정한 값 이기 때문에 "비효율적" 입니다.
martineau

2
@haridsv 그 재해 / 비 효율성의 근원입니다 definining 상수 문자열 내부 자주 호출 된 함수를. 통화 별 조회를 위해 통화 별 상수 정의를 교환 할 수 있습니다. 그렇게하면 dedent 전처리가 한 번만 실행 됩니다 . 관련 질문은 stackoverflow.com/q/15495376/611007 이 될 수 있습니다 . 각 호출마다 상수를 정의하지 않는 아이디어가 나와 있습니다 . 그러나 대안은 조회가 필요한 것 같습니다. 그러나, 그것을 저장하기에 유리한 장소를 찾는 다양한 방법이 시도되고있다. 예를 들어 def foo: return foo.x다음 행 foo.x = textwrap.dedent("bar")입니다.
n611x007

1
문자열이 디버그 모드에서만 활성화되고 로깅되지 않은 로깅을 목적으로하는 경우 비효율적이라고 생각합니다. 그렇다면 왜 여러 줄 문자열 리터럴을 기록합니까? 따라서 위의 문자열이 소비되는 것이 무엇이든 속도가 느리기 때문에 위의 비효율적 인 프로그램 (예 : 프로그램 속도를 상당히 늦추는 위치)을 찾기가 어렵습니다.
Evgeni Sergeev

52

다음 inspect.cleandoc과 같이 사용하십시오 .

def method():
    string = inspect.cleandoc("""
        line one
        line two
        line three""")

상대적 들여 쓰기는 예상대로 유지됩니다. 아래에 주석을 달았 듯이 앞에 빈 줄을 유지하려면을 사용하십시오 textwrap.dedent. 그러나 이것은 또한 첫 줄 바꿈을 유지합니다.

참고 : 구조를 명확히하기 위해 관련 컨텍스트에서 논리 코드 블록을 들여 쓰는 것이 좋습니다. 예를 들어 변수에 속하는 여러 줄 문자열 string입니다.


5
그래서 대답은 지금까지 존재하지 않았던 이유를 혼란, inspect.cleandoc이후로 존재하고 파이썬 2.6 이었고, 2008 년 ..? 물론 깨끗한 대답, 그냥 공간의 불필요한 양의 낭비 매달려 들여 쓰기 스타일, 사용하지 않습니다 특히 때문에
kevlarr

1
이 솔루션은 처음 몇 줄의 빈 텍스트 (있는 경우)를 제거합니다. 당신이 행동, 사용 textwrap.dedent을 원하지 않는 경우 docs.python.org/2/library/textwrap.html#textwrap.dedent을
joshuakcockrell

1
이것은 완벽 해요!
zzzz zzzz

23

다른 답변에서 누락 된 것으로 보이는 한 가지 옵션은 다음과 같습니다 (naxa의 의견에서 깊이 언급되어 있음).

def foo():
    string = ("line one\n"          # Add \n in the string
              "line two"  "\n"      # Add "\n" after the string
              "line three\n")

이렇게하면 올바른 정렬이 가능하고 라인을 암시 적으로 결합하며 여전히 줄 바꿈을 유지합니다. 이는 여러 줄 문자열을 사용하려는 이유 중 하나입니다.

사후 처리는 필요하지 않지만 \n줄을 끝내려는 특정 위치 에 수동으로 추가해야합니다 . 인라인 또는 별도의 문자열로 표시됩니다. 후자는 복사하여 붙여 넣기가 더 쉽습니다.


이것은 여러 줄 문자열이 아니라 암시 적으로 결합 된 문자열의 예입니다.
trk

@ trk, 문자열에 줄 바꿈 (일명 여러 줄)이 포함되어 있다는 점에서 여러 줄이지 만, OP를 사용하여 서식 문제를 피하기 위해 결합을 사용합니다.
holroy

17

더 많은 옵션. pylab이 활성화 된 Ipython에서 dedent는 이미 네임 스페이스에 있습니다. 확인했는데 matplotlib에서 가져 왔습니다. 또는 다음과 같이 가져올 수 있습니다.

from matplotlib.cbook import dedent

문서에서 그것은 텍스트 줄 바꿈에 해당하는 것보다 빠르며 ipython의 테스트에서는 실제로 빠른 테스트로 평균 3 배 빠릅니다. 또한 문자열을 구성하는 방법을 유연하게 할 수 있도록 선행 빈 줄을 버리는 이점이 있습니다.

"""
line 1 of string
line 2 of string
"""

"""\
line 1 of string
line 2 of string
"""

"""line 1 of string
line 2 of string
"""

이 세 가지 예에서 matplotlib dedent를 사용하면 동일한 합리적인 결과를 얻을 수 있습니다. textwrap dedent 함수에는 첫 번째 예제와 함께 빈 줄이 생깁니다.

명백한 단점은 textwrap이 표준 라이브러리에 있고 matplotlib가 외부 모듈이라는 것입니다.

일부 단점은 ... dedent 함수는 문자열을 정의하는 위치에서 코드를 더 읽기 쉽게 만들지 만 나중에 사용 가능한 형식으로 문자열을 가져 오려면 처리해야합니다. docstring에서는 대부분의 docstring 사용이 필요한 처리를 수행하므로 올바른 들여 쓰기를 사용해야합니다.

내 코드에 긴 문자열이 아닌 경우 긴 문자열을 둘러싸는 들여 쓰기에서 제외시키는 다음과 같은 추악한 코드가 있습니다. "아름다움이 못생긴 것보다 낫다"는 것은 분명 실패하지만, 다른 대안보다 더 단순하고 명백하다고 주장 할 수있다.

def example():
    long_string = '''\
Lorem ipsum dolor sit amet, consectetur adipisicing
elit, sed do eiusmod tempor incididunt ut labore et
dolore magna aliqua. Ut enim ad minim veniam, quis
nostrud exercitation ullamco laboris nisi ut aliquip.\
'''
    return long_string

print example()

6

빠르고 쉬운 솔루션을 원하고 개행을 입력하지 않으려면 다음과 같이 목록을 선택할 수 있습니다.

def func(*args, **kwargs):
    string = '\n'.join([
        'first line of very long string and',
        'second line of the same long thing and',
        'third line of ...',
        'and so on...',
        ])
    print(string)
    return

이것이 최선의 접근 방법은 아니지만 때때로 사용했습니다. 당신이 경우 어떻게 그것을 사용이 결합되기 전에 수정 될 수 없을거야 때문에, 당신은 목록 대신 튜플을 사용해야합니다.
Lyndsy Simon

4

나는 선호한다

    def method():
        string = \
"""\
line one
line two
line three\
"""

또는

    def method():
        string = """\
line one
line two
line three\
"""

1
함수에 들여 쓰기가 중요하다는 질문에 명시 적으로 나와 있기 때문에 질문에 대답하지 않습니다.
bignose 2012 년

@bignose이 질문은 "이상해 보인다"라는 말은 사용이 허용되지 않았다.
lk_vc

못생긴 들여 쓰기없이 어떻게 이것을 달성 할 수 있습니까?
lfender6445

@ lfender6445 글쎄요, 아마도이 문자열들을 다른 코드 들과는 별도의 파일에 넣을 수있을 것입니다.
lk_vc

3

내 두 센트는 줄 끝을 벗어나 들여 쓰기를 얻습니다.

def foo():
    return "{}\n"\
           "freq: {}\n"\
           "temp: {}\n".format( time, freq, temp )

1

여기에 대한 간단한 한 - 라이너를 찾고 온 / 제거 identation 수준 수정 , 인쇄 문서화 문자열의를 하지 않고는 단 정치 못한 볼 이 스크립트에서 "함수 외부 정지"하여, 예를 들면.

내가 한 일은 다음과 같습니다.

import string
def myfunction():

    """
    line 1 of docstring
    line 2 of docstring
    line 3 of docstring"""

print str(string.replace(myfunction.__doc__,'\n\t','\n'))[1:] 

분명히 탭 키 대신 공백 (예 : 4)으로 들여 쓰기하는 경우 다음과 같이 사용하십시오.

print str(string.replace(myfunction.__doc__,'\n    ','\n'))[1:]

문서 문자열이 다음과 같이 보이도록하려면 첫 번째 문자를 제거 할 필요가 없습니다.

    """line 1 of docstring
    line 2 of docstring
    line 3 of docstring"""

print string.replace(myfunction.__doc__,'\n\t','\n') 

이것은 클래스 메소드와 중첩 클래스에서 실패합니다.
tacaswell

1

첫 번째 옵션은 들여 쓰기가 포함 된 좋은 옵션입니다. 파이썬 스타일이며 코드에 대한 가독성을 제공합니다.

올바르게 표시하려면 다음을 수행하십시오.

print string.lstrip()

삼중 따옴표 문자열의 형식을 지정하는 가장 단순하고 깨끗한 방법 인 것 같습니다. 들여 쓰기로 인해 추가 공백이 없습니다.
Taylor Liss

4
여러 줄 문자열의 첫 줄에서 선행 공백 만 삭제합니다. 다음 줄의 서식을 지정하는 데 도움이되지 않습니다.
M. Schlenker

0

텍스트 표시 방법에 따라 다릅니다. 모두 왼쪽 정렬하려면 첫 번째 스 니펫에서와 같이 형식을 지정하거나 모든 공간을 왼쪽으로 잘라내는 줄을 반복하십시오.


5
방법 문서화 문자열 가공 도구의 작업은하지 제거하는 것입니다 모두 왼쪽에 공간을하지만, 많은 첫 번째 들여 쓰기 라인으로. 이 전략은 좀 더 정교하며 후 처리 된 문자열에서 들여 쓰기하고 존중할 수 있습니다.
Mike Graham

0

문자열의 경우 문자열을 처리 한 직후에 할 수 있습니다. docstring의 경우 대신 함수를 처리 한 후 수행해야합니다. 여전히 읽을 수있는 두 가지 솔루션이 있습니다.

class Lstrip(object):
    def __rsub__(self, other):
        import re
        return re.sub('^\n', '', re.sub('\n$', '', re.sub('\n\s+', '\n', other)))

msg = '''
      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
      tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
      veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
      commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
      velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
      cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
      est laborum.
      ''' - Lstrip()

print msg

def lstrip_docstring(func):
    func.__doc__ = func.__doc__ - Lstrip()
    return func

@lstrip_docstring
def foo():
    '''
    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
    tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
    veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
    commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
    velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
    cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
    est laborum.
    '''
    pass


print foo.__doc__

1
문서화 문자열 처리 는 PEP 257에 설명 된대로 일관된 들여 쓰기를 이미 처리해야합니다 . 예를 들어 inspect.cleandoc, 올바른 방법으로 사용하는 도구가 이미 있습니다 .
bignose 2012 년

0

비슷한 문제가 발생했습니다. 여러 줄을 사용하여 코드를 실제로 읽을 수 없었습니다.

print("""aaaa
"""   """bbb
""")

예, 처음에는 끔찍해 보일 수 있지만 포함 된 구문은 매우 복잡하고 끝에 '\ n' '와 같은 것을 추가하는 것은 해결책이 아닙니다.


0

이 함수 trim_indent를 사용할 수 있습니다 .

import re


def trim_indent(s: str):
    s = re.sub(r'^\n+', '', s)
    s = re.sub(r'\n+$', '', s)
    spaces = re.findall(r'^ +', s, flags=re.MULTILINE)
    if len(spaces) > 0 and len(re.findall(r'^[^\s]', s, flags=re.MULTILINE)) == 0:
        s = re.sub(r'^%s' % (min(spaces)), '', s, flags=re.MULTILINE)
    return s


print(trim_indent("""


        line one
            line two
                line three
            line two
        line one


"""))

결과:

"""
line one
    line two
        line three
    line two
line one
"""
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.