티스토리 뷰

반응형

Python 초보자들이 먼저 배우고, 정말 많은 곳에서 사용되는 내장 함수를 꼽으라 하면 print를 꼽을 수 있다.

 

print문은 화면에의 출력 그 이상의 기능을 할 수 있는 함수 중 하나이다. 단순 출력밖에 모른다면, 아직 print문의 잠재력을 십분 활용하지 못한다고 할 수 있다.

 

이번 포스팅에서는 print에 대하여 자세하게 알아보자. 이번 글을 파이썬 3을 기준으로 다룰 예정이니 파이썬 2에서의 print 구문은 다루지 않을 예정이다.

print에 대하여 알아보자.


1. print()

print() 함수는 파이썬 내장함수 중 하나로 특별히 다른 모듈을 활용하지 않아도 사용할 수 있는 함수이다. 실제로 함수 자체를 호출하면 다음과 같은 결과를 얻을 수 있다.

 

1
2
3
4
5
# -*- coding: utf-8 -*-
 
print(print)
 
# => <built-in function print>
cs

 

출력으로 <built-in function print>을 얻을 수 있고 즉 파이썬 내부에 지어진 함수라는 의미를 지니고 있다.

 

다르게 해석하자면, print 함수도 엄연한 함수이기에 반환 값이 있지만, 함수 그 자체를 출력하기에 return값을 쓸 일은 거의 없다고 봐도 무방하다.

 

직접 print함수를 import 하고 싶다면 기본 라이브러리 함수가 모여있는 모듈 builtins을 활용하여 print 함수를 가져올 수 있다.

 

1
2
3
4
5
6
# -*- coding: utf-8 -*-
 
import builtins
print(builtins.print)
 
# => <built-in function print>
cs

print 함수는 기본적으로 5개의 매개변수를 받으며, 첫 번째 매개변수를 제외한 4개의 매개변수 모두 키워드-전용(keyword-only) 매개변수이므로 인자를 넘겨줄 경우 직접 명시해주어야 한다.

 

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

 

1) *objects

 

*objects 매개변수는 다수의 인자를 받을 수 있는 매개변수이다. 다른 의미로, print 함수에 여러 개의 인자를 동시에 넘길 수 있다는 의미이고, 이는 objects 앞에 asterisk('*')가 붙어있는 이유이다.

 

다음과 같이 print는 자료형의 개수의 제한 없이 출력할 수 있다. 만약 개수가 1개보다 많을 경우 각 자료형을 연결하여 출력하는 모습을 확인할 수 있다.

 

1
2
3
4
5
6
7
8
9
10
print(123)
# 1 2 3
print(23, [45]) # 다른 자료형이 와도 상관없다.
# 2 3 [4, 5]
print(34, (56), {"1" : "2""3" : "4"})
# 3 4 (5, 6) {'1': '2', '3': '4'}
 
name = "Alice"
print("Hello"1, name) # 변수가 존재해도 상관없다.
# Hello 1 Alice
cs

 

또한, objects에는 기본 자료형 아무 종류가 와도 된다. 예를 들어, 다음과 같이 print는 여러 종류의 자료형을 출력할 수 있다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
print(1# class 'int'
# 1
print(3.1# class 'float'
# 3.1
print(1 + 2j) # class 'complex'
# (1+2j)
print(True# class 'bool'
# True
print("Hello"# class 'str'
# Hello
print([456]) # class 'list'
# [4, 5, 6]
print((123)) # class 'tuple'
# (1, 2, 3)
print({789}) # class 'set'
# {7, 8, 9}
print({"Alice" : 1"Bob" : 2}) # class 'dict'
# {"Alice" : 1, "Bob" : 2}
cs

 

위의 결과를 살펴보면, print에는 직접 출력하고자 하는 값이 있어도 되고, 변수가 있다면 변수의 값을 출력하는 것을 확인할 수 있다.

 

그렇다면, print 함수는 모든 자료형에 대하여 그대로의 출력을 지원하는가? 이에 대한 답은 아니다 라고 할 수 있다. print 함수 내부적으로 str()를 호출하여 string 형태로 변환한 이후 일괄적으로 문자열 처리를 하기에, 만약 자료형이 str() 및.__str__를 지원하지 않는다면 의도한 출력을 얻지 못할 수 있다.


그렇다면 직접 정의된 객체에 대한 출력을 하기 위하여서는 __str__를 정해 주어야 한다는 결론에 이를 수 있다.

 

다음 예시를 살펴보자. 먼저 Person이라는 class의 객체를 출력해야 하는 상황을 만든다고 가정하여 보자. 이 경우 class의 객체를 print에 넘겨준다면 다음과 같은 결과를 얻는다

 

1
2
3
4
5
6
7
8
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
 
john = Person("john"23)
print(john)
# <__main__.Person object at 0x0000028909D26530>
cs

 

위의 Person이라는 class에 __str__를 찾지 못하였기에 원하지 않는 출력이 나왔고, 이에 대하여 정의를 해준다면 print의 출력을 직접 정의하여 줄 수 있다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
 
    def __str__(self):
        return self.name
 
    def __repr__(self):
        return f"Person('{self.name}', '{self.age}')"
# ------------------------------------------------------------
person1 = Person("John"23)
person2 = Person("Sally"25)
print(person1, person2)
# John Sally
 
print([person1, person2])
# [Person('John', '23'), Person('Sally', '25')]
cs

 

실제로 진행하면 원하는 형태로 출력할 수 있다는 것을 확인할 수 있다.

 

또한, 위 코드에서 __repr__를 추가하였고, 이는 list 안의 객체를 출력할 때와 관련 있는 모습을 확인할 수 있다.

 

이는 list나 tuple 같은 sequence 자료형은 __str__ 메서드가 호출될 때 먼저 모든 원소들이 __repr__를 거치기 때문이다.

 

이외의 namedtuple이나 다른 추상 자료형들에도 __str__, __repr__를 추가한다면 print 함수를 원하는 방법으로 활용할 수 있을 것이다.


2) sep = ' '

sep은 separator의 약자로, 만약 여러 개의 인자가 입력되었을 때 출력 시 각 인자 간에 구분시켜줄 때 출력할 문자열이다.

 

sep에는 문자열 혹은 None이 올 수 있으며, 기본값은 띄어쓰기(' ')로 되어 있다. 만약 sep에 None이 올 경우 기본값인 띄어쓰기로 구분자가 들어가게 된다.

 

1
2
3
4
5
6
7
8
print(123, sep = None)
# 1 2 3
print(456, sep = ' ')
# 4 5 6
print(789, sep = '*')
# 7*8*9
print("a""b""c", sep = " and ")
# a and b and c
cs

 

sep은 출력 시 어떻게 출력될지 조절할 수 있는 인자 중 하나이다. 다만, 인자 간 사이에만 영향을 미치므로 양 끝에는 다른 방법을 써야 한다.


3) end = '\n'

end는 print문이 끝났을 때 출력할 문자열과 관련된 매개변수이다.

 

end에는 문자열 혹은 None이 올 수 있으며, 기본값은 줄바꿈('\n')으로 되어 있다. 만약 end에 None이 올 경우 기본값인 띄어쓰기로 구분자가 들어가게 된다.

 

1
2
3
4
5
6
7
print(123, end = " ")
print(456)
# 1 2 3 4 5 6
print()
# '\n' (줄바꿈이 숨어있다.)
print(123, end = '*')
# 1 2 3*
cs

 

이는 왜 print()가 줄바꿈을 해주는 구문인지 알 수 있게 해 준다. 아무 인자가 넘겨지지 않아도 print 함수가 끝났으므로 end의 인자인 줄바꿈('\n')이 실행되었고, 따라서 새로운 줄로 넘어가게 되었다.

 

end는 여러 개의 print 함수 간 출력을 조절할 때 유용하게 사용할 수 있는 매개변수이다.


4) file = sys.stdout

많은 사람들이 착각하는 게 print 함수는 '출력해주는 함수'라고 생각하는 것이다.

 

이는 굉장히 큰 오해이다. print 함수 자체는 콘솔 출력에 대하여 구현되어 있지 않다. 입출력 자체는 바이트 단위의 저수준 layer에서 다루어야 하는 영역이고, print는 단순히 무엇을 다루어야 할지 제공해주는 역할만 한다.

 

조금 더 자세하게 다루자면, print는 하나의 인터페이스를 제공해주는 함수로, 입출력이나 읽기/쓰기와 관련된 함수라 생각하면 될 거 같다.

 

다른 말로, print문은 콘솔에 출력하는 역할 말고, 읽기/쓰기와 관련된 기능을 할 수 있다는 이야기이다.

(이에 대한 자세한 내용은 별도의 포스팅으로 다루겠다.)

 

file 매개변수는 어떤 방식으로 출력할 것인지 정하여 주는 역할을 하며, 기본값은 sys 모듈의 stdout, 즉 콘솔 출력과 관련되었다고 할 수 있다. (sys.stdout은 정확히 파일 쓰기와 비슷하게 콘솔에 출력하게 하는 것이다.)

 

만약, 쓰기를 하고 싶다면 다음과 같이 파일 쓰기를 활용할 수 있다. 다만, binary 데이터에 대해서는 사용하면 안 된다. 

 

1
2
3
with open('file.txt''w'as file_obj:
    print("print function can write!"file = file_obj)
    file_obj.close()
cs

 

실제 이 코드를 실행하여 보면, 콘솔에 문자열이 출력되지 않고, file.txt에 문자열이 입력되어 있는 것을 확인할 수 있다.


5. flush = False

flush는 출력 버퍼와 관련된 매개변수이다. (버퍼는 입출력 시 성능 향상을 위하여 사용하기 위한 임시 공간이라고만 알고 있자. 이 글에서는 자세히 다루지 않을 것이다.)

 

만약, 3초 타이머를 print문을 통해 매 초마다 출력하도록 코드를 작성한다고 가정하자. 다음과 같이 time 모듈과 print를 조합하여 작성하였다.

 

1
2
3
4
5
6
7
8
9
import time
 
num_seconds = 3
for countdown in reversed(range(num_seconds + 1)):
    if countdown > 0:
        print(countdown, end='...')
        time.sleep(1)
    else:
        print("Go!")
cs

 

IDE에서 실행한다면 원하는 대로 매 초마다 실행되지만, 콘솔 창에서 직접 출력한다면 다음과 같이 원하는 대로 출력이 되지 않는 것을 확인할 수 있다.

 

main.py
콘솔상에서는 한번에 출력되는 것을 확인할 수 있다.

 

왜 그럴까? 운영체제마다 빠르고 안전한 입출력을 위하여 버퍼를 사용하지만, 이 경우 버퍼의 동작 방식으로 인하여 버퍼 안에 담아두었다가 한 번에 모든 print를 출력하기 때문이다.

 

따라서 이 경우를 방지하기 위하여, flush 매개변수에 True 인자를 추가하여 강제로 출력시킬 수 있다. 실제로 다음과 같이 flush 매개변수에 True를 추가한다면 원하는 방식으로 동작하는 것을 확인할 수 있다.

 

1
2
3
4
5
6
7
8
9
import time
 
num_seconds = 3
for countdown in reversed(range(num_seconds + 1)):
    if countdown > 0:
        print(countdown, end='...', flush=True)
        time.sleep(1)
    else:
        print("Go!")
cs

 

버퍼에 대한 설명은 다른 포스팅으로 찾아뵙겠다.


이것으로 print 함수에 관한 모든 매개변수를 알아보았다. 다만, print 함수의 활용은 정말로 무궁무진하다.

 

내용이 길어질 것 같으니 별도의 포스팅으로 이어서 작성하겠다.

반응형
댓글
Total
Today
Yesterday
공지사항
최근에 올라온 글
최근에 달린 댓글
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함