좋은 습관
가상환경
프로젝트가 많아질수록 다양한 버전의 파이썬이나 라이브러리로 작업하는 일이 생긴다. 별도의 파이썬 가상 환경을 만들기 위한 라이브러리는 많다. virtualenv 와 virtualenvwrapper로 파이썬 가상 환경을 간단하게 만들어보자.
virtualenv & virtualenvwrapper
virtualenv 는 파이썬 프로젝트에 필요한 패키지를 사용하기 위해 필요한 모든 실행파일을 포함하는 폴더를 생성한다.
virtualenvwrapper 는 virtualenv를 사용하여 모든 가상 환경을 한곳에 배치한다.
디버깅
파이썬 디버거, pdb 를 사용하면 디버깅을 할 수 있다. 파이썬 스크립트 파일을 대화식 인터프리터에 사용해 살펴보고 싶다면, -i 뒤 또는 -m pdb 뒤에 파일명을 적어서 실행하면 된다.
PS C:\Users\bumsu\Desktop\Python\DSA> python -i threading_with_queue.py
스레드 4: 처리 완료 0
스레드 1: 처리 완료 1
스레드 1: 처리 완료 6
스레드 4: 처리 완료 5
스레드 2: 처리 완료 3
스레드 1: 처리 완료 7
스레드 4: 처리 완료 8
스레드 2: 처리 완료 9
스레드 2: 처리 완료 12
스레드 4: 처리 완료 11
스레드 3: 처리 완료 4
스레드 2: 처리 완료 13
스레드 4: 처리 완료 14
스레드 3: 처리 완료 15
스레드 2: 처리 완료 16
스레드 4: 처리 완료 17
스레드 3: 처리 완료 18
스레드 2: 처리 완료 19
스레드 1: 처리 완료 10
스레드 5: 처리 완료 2
>>> q
<queue.Queue object at 0x0000029FF22D38E0>
>>> num_worker_threads
5
PS C:\Users\bumsu\Desktop\Python\DSA> python -m pdb threading_with_queue.py
> c:\users\bumsu\desktop\python\dsa\threading_with_queue.py(1)<module>()
-> import queue
(Pdb) help
Documented commands (type help <topic>):
========================================
EOF c d h list q rv undisplay
a cl debug help ll quit s unt
alias clear disable ignore longlist r source until
args commands display interact n restart step up
b condition down j next return tbreak w
break cont enable jump p retval u whatis
bt continue exit l pp run unalias where
Miscellaneous help topics:
==========================
exec pdb
(Pdb) help n
n(ext)
Continue execution until the next line in the current function
is reached or it returns.
(Pdb) n
> c:\users\bumsu\desktop\python\dsa\threading_with_queue.py(2)<module>()
-> import threading
(Pdb) n
> c:\users\bumsu\desktop\python\dsa\threading_with_queue.py(4)<module>()
-> q = queue.Queue()
(Pdb) n
> c:\users\bumsu\desktop\python\dsa\threading_with_queue.py(6)<module>()
-> def worker(num):
...
pdb의 명령어는 다음과 같다.
- c (continue): 프로그램을 끝까지 실행
- s (step): 코드 다음줄로 (한단계씩 코드 실행)
- n (next): 코드 다음줄로 넘어가되 프로시저 단위 실행 (step over), s와 다른 점은 어떤 함수를 만날 경우 함수 전체를 실행한 뒤 다음 줄로 넘어감.
- p (point): 표현식의 값을 출력
- l (line): 다음 실행할 코드를 몇 줄 보기
- h (help): 도움말
프로파일링
프로그램이 매우 느리게 실행되거나 예상보다 많은 메모리가 소비되는 것은 자료구조나 알고리즘을 잘못 선택했거나 비효율적으로 구현했기 때문인 경우가 많다. 다음과 같은 성능 항목을 검토할 수 있다.
- 읽기 전용 데이터는 리스트 대신 튜플을 사용
- 반복문에서 항목이 많은 리스트나 튜플 대신 제너레이터를 사용
- 문자열을 연결할 때 + 연산자로 문자열을 연결 (concatenate) 대신, 리스트에 문자열을 추가 (append) 한 후, 마지막에 리스트의 항목을 모두 하나로 연결 (join) 한다.
cProfile 모듈
cProfile 모듈은 호출 시간에 대한 세부 분석을 제공하며, 병목 현상 (bottleneck) 을 찾는 데 사용된다. 흔히 다음과 같은 형태로 사용한다.
>>> import cProfile
>>> import time
>>> def sleep():
time.sleep(5)
>>> def hello_world():
print("Hello World!")
>>> def main():
sleep()
hello_world()
>>> cProfile.run('main()')
Hello World!
160 function calls in 5.006 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 5.006 5.006 <pyshell#11>:1(main)
1 0.000 0.000 5.000 5.000 <pyshell#4>:1(sleep)
1 0.000 0.000 0.006 0.006 <pyshell#7>:1(hello_world)
1 0.000 0.000 5.006 5.006 <string>:1(<module>)
21 0.000 0.000 0.000 0.000 rpc.py:153(debug)
3 0.000 0.000 0.006 0.002 rpc.py:216(remotecall)
3 0.000 0.000 0.001 0.000 rpc.py:226(asynccall)
3 0.000 0.000 0.005 0.002 rpc.py:246(asyncreturn)
3 0.000 0.000 0.000 0.000 rpc.py:252(decoderesponse)
3 0.000 0.000 0.005 0.002 rpc.py:290(getresponse)
3 0.000 0.000 0.000 0.000 rpc.py:298(_proxify)
3 0.000 0.000 0.005 0.002 rpc.py:306(_getresponse)
3 0.000 0.000 0.000 0.000 rpc.py:328(newseq)
3 0.000 0.000 0.001 0.000 rpc.py:332(putmessage)
2 0.000 0.000 0.001 0.001 rpc.py:559(__getattr__)
3 0.000 0.000 0.000 0.000 rpc.py:57(dumps)
1 0.000 0.000 0.001 0.001 rpc.py:577(__getmethods)
2 0.000 0.000 0.000 0.000 rpc.py:601(__init__)
2 0.000 0.000 0.005 0.002 rpc.py:606(__call__)
4 0.000 0.000 0.000 0.000 run.py:412(encoding)
4 0.000 0.000 0.000 0.000 run.py:416(errors)
2 0.000 0.000 0.006 0.003 run.py:433(write)
6 0.000 0.000 0.000 0.000 threading.py:1306(current_thread)
3 0.000 0.000 0.000 0.000 threading.py:222(__init__)
3 0.000 0.000 0.005 0.002 threading.py:270(wait)
3 0.000 0.000 0.000 0.000 threading.py:81(RLock)
3 0.000 0.000 0.000 0.000 {built-in method _struct.pack}
3 0.000 0.000 0.000 0.000 {built-in method _thread.allocate_lock}
6 0.000 0.000 0.000 0.000 {built-in method _thread.get_ident}
1 0.000 0.000 5.006 5.006 {built-in method builtins.exec}
6 0.000 0.000 0.000 0.000 {built-in method builtins.isinstance}
9 0.000 0.000 0.000 0.000 {built-in method builtins.len}
1 0.000 0.000 0.006 0.006 {built-in method builtins.print}
3 0.000 0.000 0.000 0.000 {built-in method select.select}
1 5.000 5.000 5.000 5.000 {built-in method time.sleep}
3 0.000 0.000 0.000 0.000 {method '_acquire_restore' of '_thread.RLock' objects}
3 0.000 0.000 0.000 0.000 {method '_is_owned' of '_thread.RLock' objects}
3 0.000 0.000 0.000 0.000 {method '_release_save' of '_thread.RLock' objects}
3 0.000 0.000 0.000 0.000 {method 'acquire' of '_thread.RLock' objects}
6 0.005 0.001 0.005 0.001 {method 'acquire' of '_thread.lock' objects}
3 0.000 0.000 0.000 0.000 {method 'append' of 'collections.deque' objects}
2 0.000 0.000 0.000 0.000 {method 'decode' of 'bytes' objects}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
3 0.000 0.000 0.000 0.000 {method 'dump' of '_pickle.Pickler' objects}
2 0.000 0.000 0.000 0.000 {method 'encode' of 'str' objects}
2 0.000 0.000 0.000 0.000 {method 'get' of 'dict' objects}
3 0.000 0.000 0.000 0.000 {method 'getvalue' of '_io.BytesIO' objects}
3 0.000 0.000 0.000 0.000 {method 'release' of '_thread.RLock' objects}
3 0.000 0.000 0.000 0.000 {method 'send' of '_socket.socket' objects}
timeit 모듈
코드 일부분의 실행 시간을 확인하는 데 사용한다.
>>> import timeit
>>> timeit.timeit("x = 2 + 2")
0.01502549999997882
>>> timeit.timeit("x = sum(range(10))")
0.4615995000000055
단위 테스트
개별 함수 및 클래스의 메서드에 대한 테스트 코드를 작성하여 예상한 값이 맞게 나오는지 확인하는 것은 좋은 습관이다. 파이썬 표준 라이브러리는 이러한 단위 테스트 (unit test) 를 위해 doctest 와 unittest 모듈을 제공한다. 또한 외부 라이브러리인 pytest도 있다.
용어
- 테스트 픽스쳐 (test fixture): 테스트 설정을 위한 코드
- 테스트 케이스 (test case): 테스트의 기본 단위
- 테스트 스위트 (test suite): unittest.TestCase 의 하위 클래스에 의해 생성된 테스트 케이스 집합. 각 테스트 케이스의 메서드 이름은 test로 시작한ㄷ.ㅏ
- 테스트 러너 (test runner): 하나 이상의 테스트 스위트를 실행하는 객체
doctest & unittest
먼저 doctest 모듈은 모듈과 함수의 독스트링 (doctring) 안에 테스트 코드를 작성할 때 사용한다. unittest와 함께 사용할 수도 있다.
pytest
외부 라이브러리인 pytest는 사용법이 매우 쉽다. test로 시작하는 파일에서 test로 시작하는 함수를 작성하기만 하면 된다.
출처
파이썬 자료구조와 알고리즘 - 한빛미디어, 미아 스타인
'Python > 자료구조 (Data Structure)' 카테고리의 다른 글
6-1. 멀티 프로세스와 멀티 스레드 (Multi-process and Multi-thread): 파이썬 자료구조와 알고리즘 (0) | 2020.07.26 |
---|---|
5-2. 디자인 패턴 (Design Pattern): 파이썬 자료구조와 알고리즘 (0) | 2020.07.26 |
5-1. 클래스와 객체 (Class and Object): 파이썬 자료구조와 알고리즘 (0) | 2020.07.25 |
4. 구조와 모듈 (Structure and Module): 파이썬 자료구조와 알고리즘 (0) | 2020.07.22 |
3. 컬렉션 (Collection): 파이썬 자료구조와 알고리즘 (0) | 2020.07.21 |