programing

목록에 추가하는 것보다 목록 이해가 훨씬 빠른 이유는 무엇입니까?

i4 2023. 6. 10. 08:18
반응형

목록에 추가하는 것보다 목록 이해가 훨씬 빠른 이유는 무엇입니까?

왜 목록에 추가하는 것보다 목록 이해가 훨씬 빠른지 궁금했습니다.저는 그 차이가 단지 표현적인 것이라고 생각했지만, 그렇지 않습니다.

>>> import timeit 
>>> timeit.timeit(stmt='''\
t = []
for i in range(10000):
    t.append(i)''', number=10000)
9.467898777974142

>>> timeit.timeit(stmt='t= [i for i in range(10000)]', number=10000)
4.1138417314859

목록 이해 속도가 50% 더 빠릅니다. 왜죠?

목록 이해는 기본적으로 정규 학생들에게 "통사적 설탕"일 뿐입니다.for루프. 이 경우 더 나은 성능을 발휘하는 이유는 목록의 추가 속성을 로드하고 각 반복 시 함수로 호출할 필요가 없기 때문입니다.즉, 일반적으로 함수의 프레임이나 다른 경우의 여러 함수를 일시 중단했다가 재개하는 것이 요청 시 목록을 만드는 것보다 느리기 때문에 목록 이해가 더 빨리 수행됩니다.

다음 예를 생각해 보십시오.

In [1]: def f1(): 
   ...:         l = [] 
   ...:         for i in range(5): 
   ...:             l.append(i) 
   ...:     
   ...:  
   ...: def f2(): 
   ...:     [i for i in range(5)] 
   ...:                                                                                                                                                                                                     

In [3]: import dis                                                                                                                                                                                          

In [4]: dis.dis(f1)                                                                                                                                                                                         
  2           0 BUILD_LIST               0
              2 STORE_FAST               0 (l)

  3           4 LOAD_GLOBAL              0 (range)
              6 LOAD_CONST               1 (5)
              8 CALL_FUNCTION            1
             10 GET_ITER
        >>   12 FOR_ITER                14 (to 28)
             14 STORE_FAST               1 (i)

  4          16 LOAD_FAST                0 (l)
             18 LOAD_METHOD              1 (append)
             20 LOAD_FAST                1 (i)
             22 CALL_METHOD              1
             24 POP_TOP
             26 JUMP_ABSOLUTE           12
        >>   28 LOAD_CONST               0 (None)
             30 RETURN_VALUE

In [5]:                                                                                                                                                                                                     

In [5]: dis.dis(f2)                                                                                                                                                                                         
  8           0 LOAD_CONST               1 (<code object <listcomp> at 0x7f397abc0d40, file "<ipython-input-1-45c11e415ee9>", line 8>)
              2 LOAD_CONST               2 ('f2.<locals>.<listcomp>')
              4 MAKE_FUNCTION            0
              6 LOAD_GLOBAL              0 (range)
              8 LOAD_CONST               3 (5)
             10 CALL_FUNCTION            1
             12 GET_ITER
             14 CALL_FUNCTION            1
             16 POP_TOP
             18 LOAD_CONST               0 (None)
             20 RETURN_VALUE

Disassembly of <code object <listcomp> at 0x7f397abc0d40, file "<ipython-input-1-45c11e415ee9>", line 8>:
  8           0 BUILD_LIST               0
              2 LOAD_FAST                0 (.0)
        >>    4 FOR_ITER                 8 (to 14)
              6 STORE_FAST               1 (i)
              8 LOAD_FAST                1 (i)
             10 LIST_APPEND              2
             12 JUMP_ABSOLUTE            4
        >>   14 RETURN_VALUE

In [6]:   

첫 번째 함수의 오프셋 18에서 볼 수 있습니다.append목록 이해를 사용하는 두 번째 함수에는 그런 것이 없는 반면 속성.모든 추가 바이트 코드는 추가 접근을 더 느리게 만들 것이고 이 경우에는 로드가 발생하기 때문입니다.append각 반복에서 속성은 결국 목록 이해만을 사용하여 코드를 두 번째 함수보다 약 두 배 느리게 만듭니다.

검색 및 로드에 소요되는 시간을 고려하는 것도append함수, 목록은 Python에서 한 번에 하나의 항목을 작성하는 것이 아니라 C로 작성되기 때문에 여전히 목록 이해가 더 빠릅니다.

# Slow
timeit.timeit(stmt='''
    for i in range(10000):
        t.append(i)''', setup='t=[]', number=10000)

# Faster
timeit.timeit(stmt='''
    for i in range(10000):
        l(i)''', setup='t=[]; l=t.append', number=10000)

# Faster still
timeit.timeit(stmt='t = [i for i in range(10000)]', number=10000)

언급URL : https://stackoverflow.com/questions/30245397/why-is-a-list-comprehension-so-much-faster-than-appending-to-a-list

반응형