라떼는말이야

[python] 코딩 테스트에서 print를 할 때는 무조건 포매팅(formatting) 사용하세요!! 본문

알고리즘/코딩 테스트

[python] 코딩 테스트에서 print를 할 때는 무조건 포매팅(formatting) 사용하세요!!

MangBaam 2022. 1. 28. 19:11
반응형

파이썬에는 다양한 출력 방법이 존재한다.

코딩 테스트 같은 경우 시간 복잡도와 공간 복잡도가 아주 중요한데 특히 시간 복잡도에서 좌절을 겪는 경우가 상당히 많다.

이 글은 알고리즘 문제를 풀다가 동일한 알고리즘인데 시간 차이가 많이 나는 경우를 발견해서 작성하게 되었다.


파이썬의 다양한 출력 방법

문자열 결합 방식

가장 기본적인 방법이다.

a, b, c = 1, 2, 3
print("a는:", a, "b는:",b , "c는:", c)
print("a는:" + str(a), "b는:" + str(b) , "c는:" + str(c))

,(comma)로 이어서 출력할 수 있다. 이때 a, b, c는 정수 타입이지만 별도의 변환 없이 출력이 가능하다.

+(plus)로 이어 줄 수도 있다. 하지만 이 방법은 문자열 자체를 이어서 출력하는 방식이기 때문에 정수 타입인 a, b, c는 str() 함수를 사용해 문자열 타입을 바꿔줘야 이어 줄 수 있다.

 

이하 방식들을 formatting이라고 부를 수 있음

% operator 방식 (옛날 방식)

C언어를 해 본 사람이라면 익숙한 방식일 것이다. % 를 사용해 출력하는 방식이다.

이 방식은 옛날 방식이다. 옛날 방식이라고 하는 근거는 파이썬 공식 문서에 있다.

a, b, c = 1, 2, 3
print("a: %d, b: %d, c: %d"%(a, b, c))

%d는 데이터의 타입을 표현한다. %d는 decimal(10진수 숫자)를 의미한다.

 

str.foramt 방식

파이썬 3.0 이상부터 지원하는 방식이며, 위의 % operator 방식과 비슷하지만 가독성이 더 좋게 느껴진다.

하지만 매개 변수가 많아질수록 가독성이 급격하게 안 좋아진다.

{ } 안에 숫자 n를 넣으면 n 번째 매개 변수를 참조할 수 있다.

a, b, c = 1, 2, 3
print("a: {}, b: {}, c: {}".format(a, b, c))

 

f-string 방식

파이썬 3.6 이상 부터 지원하는 방식이다. 가장 가독성이 좋고 가장 빠르다고 알려져 있다.

출력할 문자열 앞에 f나 F를 붙이면 사용할 수 있다. { } 안에는 출력할 변수가 직접 들어간다. (연산도 가능)

a, b, c = 1, 2, 3
print(f"a: {a}, b: {b}, c: {c}")

 


테스트

https://www.acmicpc.net/problem/6588

 

6588번: 골드바흐의 추측

각 테스트 케이스에 대해서, n = a + b 형태로 출력한다. 이때, a와 b는 홀수 소수이다. 숫자와 연산자는 공백 하나로 구분되어져 있다. 만약, n을 만들 수 있는 방법이 여러 가지라면, b-a가 가장 큰

www.acmicpc.net

 

 

이 문제를 풀다가 동일한 알고리즘에 출력 방식에 따라 시간 차이가 많이 나는 경우를 발견하게 되었다.

그래서 각 출력 방식에 따라 시간을 테스트해 보았다.

코드는 다음과 같다.

import time

MAX = 100000
check = [0] * (MAX+1)
check[0] = check[1] = True

prime = []

for i in range(2, int(MAX**0.5)+1):
    if not check[i]:
        prime.append(i)
        j = i+i
        while(j < MAX):
            check[j] = True
            j += i
            
prime = prime[1:]


time_dic = dict()
############################################################ [문자열 결합] 시간 체크 시작
start_time = time.time()

for n in range(6, MAX+1, 2):
    if n == 0:
        break
    for p in prime:
        if check[n-p] == False:
            print(n, "=", p, "+", n-p)
            break
            
############################################################ 시간 체크 끝

time1 = time.time() - start_time
time_dic["문자열 결합"] = time1

############################################################ [f-string] 시간 체크 시작
start_time = time.time()

for n in range(6, MAX+1, 2):
    if n == 0:
        break
    for p in prime:
        if check[n-p] == False:
            print(f"{n} = {p} + {n-p}")
            break
        
############################################################ 시간 체크 끝
time2 = time.time() - start_time
time_dic["f-string"] = time2

############################################################ [%operator] 시간 체크 시작
start_time = time.time()

for n in range(6, MAX+1, 2):
    if n == 0:
        break
    for p in prime:
        if check[n-p] == False:
            print("%d = %d + %d"%(n, p, n-p))
            break
        
############################################################ 시간 체크 끝
time3 = time.time() - start_time
time_dic["% operator"] = time3

############################################################ [str.format] 시간 체크 시작
start_time = time.time()

for n in range(6, MAX+1, 2):
    if n == 0:
        break
    for p in prime:
        if check[n-p] == False:
            print("{} = {} + {}".format(n, p, n-p))
            break
        
############################################################ 시간 체크 끝
time4 = time.time() - start_time
time_dic["str.format"] = time4

print("=" * 100)
print(f"상한: {MAX}")

ranking = sorted(time_dic.items(), key=lambda x: x[1])
print()
for i, rank in enumerate(ranking):
    print(f'{i+1}등 -> {rank[0]} 방식: {rank[1]}초\n')

코드를 잘 보면 알겠지만 완전히 동일한 알고리즘을 출력 방식만 다르게 하여 4회 반복한다.

상한은 10만으로 정했다. (문제에서는 100만이지만 테스트 시간이 너무 오래 걸리는 이유로...)

 

반복문(for문)을 돌기 전 시작 시간을 세팅하고, 반복문을 빠져나온 후 시간을 측정했다.

그 결과들을 시간 순서대로 정렬해서 순위를 매겨봤다.

 


 

테스트 결과

테스트 결과

 

1, 2, 3등의 방식이 모두 거의 비슷하게 나온 것에 비해 4등의 문자열 결합 방식은 거의 6배나 오래 걸리는 결과가 나왔다.

여러 번의 테스트 결과 1, 2, 3등은 조금씩 엎치락뒤치락했지만 4등의 문자열 결합 방식은 매번 아주 오래 걸렸다.

 

결론

코딩 테스트에서 출력을 하는 부분이 많지 않다면 어떤 방식을 이용하나 그 차이는 크지 않을 것이다. 하지만 위 문제처럼 굉장히 많은 출력이 필요한 문제는 같은 알고리즘이더라도 출력 방식에 따라 큰 차이가 발생할 수 있다.

기본적으로 포매팅을 사용하는 방식이 훨씬 빠르고, 그들 간의 큰 차이는 보이지 않는다고 하지만 (파이썬 3.6 이상 버전을 사용한다면) 가장 가독성이 좋고, 빠른 f-string 방식을 사용하는 것을 추천한다.

 

적어도 포매팅을 사용할 수 있는 출력 조건이라면 무조건 포매팅을 사용하자.

 

반응형
Comments