본문 바로가기

잡다

[python] f-string(Literal String)과 string concatenation의 비교

f-string은 파이썬에서 문자열 덧셈을 가장 효율적으로 처리한다고 알려져 있으며, 이에 관련된 벤치마크 결과도 존재한다. 그렇다면 정말 f-string이 효율적인지 알아보기 위해 f-string과 문자열 concatenation을 수행하고 값을 반환하는 함수를 dis 모듈을 통해 디컴파일하여 바이트 코드 수준으로 비교해보자.

 

dis — Disassembler for Python bytecode

Source code: Lib/dis.py The dis module supports the analysis of CPython bytecode by disassembling it. The CPython bytecode which this module takes as an input is defined in the file Include/opcode....

docs.python.org

import dis

def test1(s: str):
    return f'^{s}'
def test2(s: str):
    return '^' + s

print('test1')
dis.dis(test1)
print('test2')
dis.dis(test2)

코드가 출력한 결과

 바이트 코드 수준에서는 두가지 문자열 처리 방식에 대한 함수가 동일한 사이클 수를 요구하는 모습을 볼 수 있었다. 세부적으로는 f string은 FORMAT_VALUE, BUILD_STRING을, string concatenation은 BINARY_OP(덧셈 연산)을 수행하여 서로 다른 과정을 가지고 있었지만, 현재 상황에서는 두가지 방식이 동일한 효율을 보였다.

 단, 이러한 특성은 문자열 덧셈이 단 한번 일어날 때까지만 적용되며, + 기호를 이용하여 string concatenation을 많이 수행할 수록 두가지 방식의 효율 차이가 벌어지게 된다 이를 알기 위해 다음 코드를 실행해보자.

import dis

def test1(s: str):
    return f'^{s}{s}{s}{s}{s}{s}'
def test2(s: str):
    return '^' + s + s + s + s + s + s

print('test1')
dis.dis(test1)
print('test2')
dis.dis(test2)

코드 실행 결과. f-string 방식의 효율이 더 좋다.

 덧셈을 한번만 수행할 때는 두가지 문자열 처리 방식이 동일한 사이클 수를 요구했으나, 덧셈 연산이 많아지자 f-string이 요구하는 사이클의 수가 더 적은 모습을 보인다. 그 이유는 두가지 방식이 문자열 하나를 추가할 때마다 요구하는 사이클의 수가 다르기 때문이다.

 f-string은 포맷 내에 하나의 문자열이 추가될 때마다 LOAD_FAST, FORMAT_VALUE을 호출한다. 이때 각 바이트 코드는 2 사이클을 요구하므로 한 개의 문자열마다 4 사이클이 추가된다. 전체 문자열을 처리하는 BUILD_STRING에 2 사이클이 요구되기는 하나, 단 한번만 호출되므로 성능상 큰 비중을 차지하지는 않는다.
 반면 string concatenation은 문자열 덧셈을 수행할 때마다 LOAD_FAST, BINARY_OP을 호출한다. 이때 BINARY_OP 바이트 코드는 4 사이클을 요구하므로, 한 개의 문자열마다 6 사이클이 추가된다.

문자열 N개를 추가하기 위해 필요한 사이클 수를 따지면 다음과 같다.

  • f-string: 4N( LOAD_FAST: 2, FORMAT_VALUE: 2 ) + 2( BUILD_STRING )
  • string concatenation: 6N( LOAD_FAST: 2, BINARY_OP: 4 )

 즉, 문자열에 대한 덧셈을 2회 이상 수행하는 경우 f-string의 효율이 string concatenation을 넘게 된다. 따라서 문자열을 연결해야 하는 경우 concatenation보다는 f-string을 사용하는 편이 더 좋아 보인다.


 f-string이 파이썬 내 문자열 처리 방식 중에서 가장 효율적이라는 것은 벤치마크 결과를 통해 알고 있었지만 이를 비교해본 것은 처음이다. 나는 dis 모듈같이 바이트 코드를 제공하는 모듈이 존재할줄은 생각도 못했다. 파이썬의 장점 중 하나가 모듈의 다양성이라는 점이 체감되는 활동이었다.