print() 함수의 새로운 면모(sep, end, file, flush)

Jane·2020년 11월 27일
12
post-thumbnail

이 글은 "오래 알고 지낸 print... 너 이렇게 💰이 많은... 아니 매개변수가 많은 아이였어...?"라는 깨달음을 바탕으로 작성된 글입니다.

사건의 발단

for x in array:
    for y in x:
        print(y, end=" ")
    print()

2차원 배열을 출력하기 위해 print의 end를 쓰다가 문득 다른 키워드 인자들에는 어떤 것들이 있는지 궁금해졌다.


공식 문서에 숨어있던 (나만 몰랐던 네 모습)

공식 문서(📂)를 찾아보니 print()에는 생각보다 많은 기능이 있었다.

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)

오래 알고 지낸 print... 너 이렇게 💰이 많은... 아니 매개변수가 많은 아이였어...?

라는 감격도 잠시, 공식 문서의 설명을 읽어도 잘 이해가 안 되어 python console에서 help 선생님께 도움을 요청했다. 모르는 것이 있을 때는 help 선생님이 거의 다 알려주신다.

>>> help(print)
Help on built-in function print in module builtins:

print(...)
    print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
    
    Prints the values to a stream, or to sys.stdout by default.
    Optional keyword arguments:
    file:  a file-like object (stream); defaults to the current sys.stdout.
    sep:   string inserted between values, default a space.
    end:   string appended after the last value, default a newline.
    flush: whether to forcibly flush the stream.

sep & end

sep와 end는 코드 실습을 통해 직관적으로 이해할 수 있었다.
sep는 받은 value 사이에 삽입할 문자열을, end에는 마지막 value 뒤에 붙이고 싶은 value를 적어주면 된다. (end의 기본값은 newline이어서 파이썬에서는 print()함수만 실행해도 줄바꿈이 된다.)

>>> print('apple1', 'apple2', 'apple3', sep = '🍎', end = '🌳')
# result: apple1🍎apple2🍎apple3🌳

문제는 fileflush인데... 이해한 내용을 바탕으로 최대한 쉽게(?) 설명해 보겠다.

file

file: a file-like object (stream); defaults to the current sys.stdout.

print()함수는 기본적으로 objects를 텍스트 스트림 file로 출력하는 기능을 하는데, file이라는 키워드 인자에 write(string) 메서드가 포함된 파일 객체를 설정해주면 출력하는 것 뿐만 아니라 파일에 내용을 쓰는 것도 가능해진다.

file object(= file-like object = stream): 하부 자원에 대해 read()나 write()와 같은 파일 지향적 API를 드러내는 객체 📂

이제 print()함수를 이용하여 파일의 내용을 써 보자! 📂

with open('test1.txt', 'w') as f:
    print('Hello World!', file=f)

위의 코드를 실행한 뒤 test1.txt 파일을 열어보면 "Hello World!"가 정상적으로 입력된 것을 확인할 수 있다.

만약 write(string) 메서드가 포함된 파일 객체가 없다면, file의 초기값은 sys.stdout으로 설정되어 있다. stdout은 standard out(표준 출력)의 약자로 print()함수의 기본값은 화면에 내용을 출력하는 것으로 설정되어 있다는 뜻이다. (이는 우리 모두 이미 아는 내용이다.)


다음으로 flush에 대해 살펴보자.

flush

flush: whether to forcibly flush the stream.

공식 문서에 따르면 일반적으로 출력의 버퍼링 여부는 file에 의해 정해지지만, flushTrue로 설정하면 스트림이 강제로 flush(clear)된다고 한다. 즉, print() 함수의 출력 값이 buffered 상태 일 때 flush=True로 설정해주면 buffered된 출력값을 바로 목적지에 도달시킬 수 있다.

import time 

for i in range(10): 
	print(i, end =' ', flush = True) 
	time.sleep(1) 

위와 같이 flush = True로 설정하면 print()함수가 실행될 때마다 flush가 되어 1초에 한 글자씩 출력된다.

그런데 실습해보니 flush=False인 상태에서도 flush가 되고 있는(?) 현상을 마주했다.

너 쉽지 않은 아이구나?

파이썬의 end parameter로 설정된 \n의 경우 바로 내용이 flush되지만📂, ' '의 경우 output이 buffered 상태여서 9초가 지난 후 10초에 모든 숫자가 동시에 출력되어야 한다.

import time

for i in range(10):
    print(i, end = ' ')
    time.sleep(1) 

그러나 파이참에서 위의 코드를 실행해 보았더니 1글자씩 공손하게 출력되었다.

(update) 이 문제 때문에 몇 시간을 삽질했는데 커뮤니티에 질문을 올린 결과 다른 분들은 buffered된 대로 잘 출력이 된다고 한다.

흠 이상하네요? 위의 코드 작동시켜보니 0-9 한번에, 이후 하나씩 프린트됩니다. 말씀하신대로 버퍼인 상태에서 마지막에 한번에 출력되는 것이 맞는 것 같은데요… 뭔가 실행에 착오가 있었던게 아닐까요?

터미널에서 python(3이상)을 실행시켜놓고 해보시겠어요?

조언을 참고하여 파이참과 주피터 노트북이 아닌 repl.it과 터미널에서 실행했더니 결과가 제대로 출력되었다.

  • repl.it 실행 결과

  • 터미널 실행 결과

고마워 print()

30분만 알아가려고 했던 print()는 나와 반나절이나 함께하게 되었지만 두 가지 교훈을 주었다.

  1. 다음부터 이러한 종류의 문제가 발생했을 때는 일단 터미널이나 repl.it 등에서 실행시켜보자. 코드가 아닌 실행 환경의 문제일 수도 있다.
  2. 삽질은 좋지만 문제의 경중에 비해 너무 많은 시간이 소요된다면 과감하게 질문하자. (print 네가 안 중요하다는 건 아니야... 다만...(생략))

이번 포스팅이 print()함수를 이해하는데 조금이나마 도움이 되셨다면 💚를 눌러주세요😉

3개의 댓글

comment-user-thumbnail
2021년 10월 15일

flush.. 감사합니다

1개의 답글
comment-user-thumbnail
2022년 8월 7일

글을 재미있게 작성하시네요. 잘 읽고 갑니다.

답글 달기