본문 바로가기
DEVLOG/개발일기

파이썬(Python) 코드를 효율적으로 작성하는 법 Part 1

2019. 9. 12.
반응형

1. 내장함수(built-in functions)를 사용하라.

파이썬으로도 효율적인 코드를 작성할 수 있습니다. 하지만 C언어로 작성된 내장함수를 이기기는 힘듭니다. 내장함수는 정말 빠릅니다.

파이썬 내장함수는 링크에서 확인할 수 있습니다.

Built-in Functions
input() open()
int() ord()
isintance() pow()
issubclass() print()
iter() property()

 

2. 긴 문자열을 합칠 때는 join()을 사용하라.

여러 문자열들을 합칠 때 "+"를 사용할 수 있습니다. 파이썬에서 string은 immutable하기 때문에, "+"연산을 할 때 새 문자열을 만들고 기존 내용을 복사해야합니다. join()을 사용하십시오.

# This is good to glue a large number of strings
for chunk in input():
    my_string.join(chunk)

 

3. 변수를 swap할 때는 다중할당을 사용하라.

# 우아하고 빠른 코드
x, y = y, x

# 이 방법은 더 느립니다
temp = x
x = y
y = temp

 

4. 가능하면 지역 변수를 사용하라

파이썬은 전역 변수(global variable)를 검색하는 것보다 지역 변수(local variable)를 검색하는 것이 더 빠릅니다. “global”키워드를 사용하지 마십시오.

 

5. 가능하면 "in"을 사용하라

일반적으로 원소인지 확인하기 위해서 "in" 키워드를 사용하십시오. 깔끔하고 빠릅니다.

for key in sequence:
    print("found")

 

6. importing을 통한 속도 향상

"import"문을 함수에 넣고 필요할 때만 import를 사용하십시오. 즉, 일부 모듈은 즉시 필요하지 않을 경우 나중에 import 하세요. 예를 들면, 시작할 때 긴 모듈 목록을 가져오지 않으면서 프로그램 속도를 높일 수 있습니다. 이 방법은 프로그램의 전반적인 성능을 향상시키지는 않습니다. 다만, 모듈 로딩 시간을 보다 균등하게 분배할 수 있습니다.

 

7. 무한루프를 생성한다면 "while 1"을 사용하라

가끔 무한루프를 사용할 일이 있을 것입니다. (listening socket같은 경우..)

"while True"를 사용해도 되지만, "while 1"은 한 단계 빠른 방법입니다. 

while 1:
    # do stuff, faster with while 1
while True:
    # do stuff, slower with while True

 

8. List Comprehension을 사용하라

Python 2.0부터 List Comprehension을 사용해 for문과 while문을 대체할 수 있게 되었습니다. List Comprehension은 파이썬 인터프리터가 루프를 돌면서 예측 가능한 패턴을 발견할 수 있게 최적화되어 있어서 더 빠릅니다.

또한 List Comprehension은 가독성이 뛰어나고(functional programming), 대부분의 경우 카운팅을 위한 하나의 변수만을 저장합니다.

# 파이썬스러운 방법
evens = [i for i in range(10) if i%2 == 0]

# 파이썬스럽지 않은 방법
i = 0
evens = []
while i < 10:
    if i%2 == 0: evens.append(0)
    i += 1

 

9. 매우 긴 sequence에는 xrange()를 사용하라

xrange()는 한 번에 하나의 정수 원소만 생성하므로 시스템 메모리를 절약할 수 있습니다. range()와 달리 전체 목록을 제공하므로, 루프를 도는 중에 불필요한 overhead가 발생합니다.

 

10. On demand로 데이터를 얻을 때는 파이썬 제너레이터(generator)를 사용하라

이 방법은 메모리를 절약할뿐만 아니라 성능을 향상시킬 수 있습니다. 비디오를 스트리밍하는 경우, 전체 스트림이 아닌 몇 바이트씩 보낼 수 있습니다.

chunk = (1000 * i for i in xrange(1000))

chunk.next() # 0
chunk.next() # 1000
chunk.next() # 2000

 

11. itertools 모듈을 배워라

itertools 모듈은 iteration과 combination에 굉장히 효율적입니다.

리스트 [1, 2, 3]의 모든 순열을 단 3줄로 생성할 수 있습니다.

import itertools
iter = itertools.permutations([1, 2, 3])
list(iter)
# [(1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1), (3, 1, 2), (3, 2, 1)]

 

12. 정렬된 순서로 리스틀 유지하기 위해 bisect 모듈을 배워라

bisect 모듈은 정렬된 리스트에 원소를 삽입 후, 다시 정렬할 필요 없도록 관리해줍니다.

import bisect
bisect.insort(list, element)

리스트가 매우 길 경우에 더 효율적입니다.

 

13. 파이썬 리스트(List)는 실제로 배열이라는 것을 이해하라

파이썬의 리스트는 일반적인 single-linked list로 구현되지 않습니다. 파이썬에서 리스트는 배열입니다. 즉, 목록의 처음부터 검색하지 않고 일정한 시간 O(1)동안 indexing을 통해 리스트에서 요소를 검색할 수 있습니다. 파이썬 개발자는 리스트에 insert()를 사용할 때 생각해봐야합니다.

list.insert(0, element)

이 방법은 기존 원소들의 index를 모두 변경해야 하기 때문에 비효율적입니다.

 

list.append()

append()를 사용할 경우 리스트의 끝에 새로운 원소를 추가할 수 있습니다.

하지만 처음과 끝에 삽입/제거를 할 경우 deque를 사용하십시오. 파이썬에서 deque는 double-linked list로 구현되었기 때문에 빠릅니다.

 

14. 원소 유무를 확인할 때는 dictset을 사용하라

파이썬은 dictionary 또는 set에 원소가 존재하는지 체크하는 것이 굉장히 빠릅니다. dict와 set은 hash table로 구현되었기 때문입니다.

O(1)만큼 빠를 수 있습니다. 그러므로 존재 유무를 자주 확인해야 될 경우 컨테이너로 dict 또는 set을 사용하십시오.

# list를 사용할 경우 느림
mylist = ['a', 'b', 'c']
print('c' in mylist) # True

# set을 사용할 경우 빠름
myset = set(['a', 'b', 'c'])
print('c' in myset) # True

 

15. Use sort() with Schwartzian Transform

The native list.sort() function is extraordinarily fast. Python will sort the list in a natural order for you. Sometimes you need to sort things unnaturally. For example, you want to sort IP addresses based on your server location. Python supports custom comparison so you can do list.sort(cmp()), which is much slower than list.sort() because you introduce the function call overhead. If speed is a concern, you can apply the Guttman-Rosler Transform, which is based on the Schwartzian Transform. While it’s interesting to read the actual algorithm, the quick summary of how it works is that you can transform the list, and call Python’s built-in list.sort() -> which is faster, without using list.sort(cmp()) -> which is slower.

 

Schwartzian transform - Wikipedia

In computer programming, the Schwartzian transform is a technique used to improve the efficiency of sorting a list of items. This idiom[1] is appropriate for comparison-based sorting when the ordering is actually based on the ordering of a certain property

en.wikipedia.org

 

16. Cache results with Python decorator

"@" 기호는 파이썬 decorator입니다. @기호는 tracing뿐만 아니라 locking이나 logging에도 사용하십시오. 나중에 필요한 결과를 기억하도록 Python 함수를 사용할 수 있습니다. 이 기법을 "memoization"이라고 합니다.

from functools import wraps
def memo(f):
    cache = {}
    @wraps(f)
    def wrap(*arg):
        if arg not in cache:
            cache['arg'] = f(*arg)
        return cacche['arg']
    return wrap

Fibonacci 함수에 사용할 수도 있습니다.

@memo
def fib(i):
    if i < 2:
        return 1
    return fib(i-1) + fib(i-2)

여기서 핵심 아이디어는 간단합니다. 계산한 각 피보나치 항을 기억하도록 decorate하면 됩니다. 캐시에 있으면 다시 계산할 필요가 없습니다.

 

17. Python GIL(global interpreter lock)을 이해하라

CPython의 메모리 관리는 trhead로부터 안전하지 않기 때문에 GIL이 필요합니다. 단순히 여러 스레드를 만들고 멀티코어 컴퓨터에서 Python이 더 빨리 실행되기를 바랄 수 없습니다. GIL이 multiple native threads가 한 번에 Python 바이트 코드를 실행하지 못하게하기 때문입니다. 즉, GIL은 모든 스레드를 직렬화합니다. 그러나 thread를 사용하여 Python 코드 외부에서 독립적으로 실행되는 여러 분기 프로세스를 관리하여 프로그램 속도를 높일 수 있습니다.

 

 

파이썬(Python) 코드를 효율적으로 작성하는 법 Part 2

파이썬(Python) 코드를 효율적으로 작성하는 법 Part 1 1. 내장함수(built-in functions)를 사용하라. 파이썬으로도 효율적인 코드를 작성할 수 있습니다. 하지만 C언어로 작성된 내장함수를 이기기는 힘듭니다...

deepwelloper.tistory.com

 

반응형

댓글