Skip to content

Commit f26fe37

Browse files
committed
better way 80 정리
1 parent 79416c3 commit f26fe37

File tree

2 files changed

+170
-0
lines changed

2 files changed

+170
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,4 @@
115115
[77. setUp, tearDown, setUpModule, tearDownModule 을 사용해 각각의 테스트를 격리하라](./summary/BetterWay77.md)
116116
[78. 목을 사용해 의존 관계가 복잡한 코드를 테스트하라](./summary/BetterWay78.md)
117117
[79. 의존 관계를 캡슐화해 모킹과 테스트를 쉽게 만들라](./summary/BetterWay79.md)
118+
[80. pdb 를 사용해 대화형으로 디버깅하라](./summary/BetterWay80.md)

summary/BetterWay80.md

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
# 80. pdb 를 사용해 대화형으로 디버깅하라
2+
3+
## 1. 버그 찾기
4+
5+
- 출력을 통해 버그 찾기
6+
- 테스트를 작성하여 버그 찾기
7+
- 파이선 내장 대화형 디버거를 사용하여 버그 찾기
8+
9+
## 2. 파이선 내장 대화형 디버거 pdb
10+
11+
- 문제를 조사하기에 가장 적합한 지점에서 프로그램이 디버거를 초기화할 수 있게 프로그램 변경
12+
- `breakpoint` 내장 함수 호출
13+
- `pdb` 내장 모듈 임포트
14+
- `set_trace` 함수 실행
15+
- breakpoint 함수 실행되자마자, 다음 줄로 실행이 옮겨지기 전에 프로그램 실행이 일시 중단
16+
- 대화형 파이선 쉘 실행
17+
18+
```python
19+
# always_breakpoint.py
20+
import math
21+
22+
def compute_rmse(observed, ideal):
23+
total_err_2 = 0
24+
count = 0
25+
for got, wanted in zip(observed, ideal):
26+
err_2 = (got - wanted) ** 2
27+
breakpoint() # 여기서 디버거를 시작함
28+
total_err_2 += err_2
29+
count += 1
30+
31+
mean_err = total_err_2 / count
32+
rmse = math.sqrt(mean_err)
33+
return rmse
34+
35+
result = compute_rmse(
36+
[1.8, 1.7, 3.2, 6],
37+
[2, 1.5, 3, 5])
38+
print(result)
39+
```
40+
41+
```python
42+
$ python3 always_breakpoint.py
43+
> always_breakpoint.py(12)compute_rmse()
44+
-> total_err_2 += err_2
45+
(Pdb)
46+
```
47+
48+
- `(Pdb)` 프롬프트에서 `p` 명령을 통해 지역 변수 이름을 입력하면 변수에 저장된 값 출력
49+
- `locals` 내장 함수 호출하면 모든 지역 변수 목록을 볼 수 있음
50+
- `(Pdb)` 프롬프트에서 모듈 임포트, 새 객체 생성, `help` 내장함수 실행, 프로그램 일부 변경 가능
51+
- `Pdb` 명령
52+
- `where`
53+
- 현재 실행 중인 프로그램의 호출 스택 출력
54+
- 프로그램의 현재 위치 파악 가능, `breakpoint` 트리거 발동 위치 파악 가능
55+
- `up`, `u`
56+
- 실행 호출 스택에서 현재 관찰 중인 함수를 호출한 쪽으로 호출 스택 영역을 이동해서 해당 함수의 지역 변수 관찰 가능
57+
- `down`, `d`
58+
- 실행 호출 스택에서 한 수준 아래로 호출 스택 영역 이동
59+
- `step`
60+
- 다음 줄까지 실행한 다음 제어를 디버거로 돌려서 디버거 프롬프트 표시
61+
- 소스 코드 다음 줄에 함수를 호출하는 부분이 있다면 해당 함수의 첫 줄에서 디버거로 제어가 돌아옴
62+
- `next`
63+
- `step` 과 유사, 차이점은 함수 호출 부분에서 해당 함수 반환 후 제어가 디버거로 돌아옴
64+
- `return`
65+
- 현재 함수에서 반환될 때까지 프로그램을 실행 한 후 제어가 디버거로 돌아옴
66+
- `continue`
67+
- 다음 중단점에 도달할 때까지 프로그램을 계속 실행
68+
- breakpoint 호출이나 디버거에서 설정한 중단점에서 제어가 디버거에게 돌아옴
69+
- 실행하는 중에 중단점을 만나지 못하면 프로그램 계속 실행
70+
- `quit`
71+
- 디버거에서 나가면서 프로그램 중단
72+
73+
- `breakpoint` 함수는 프로그램 어디서든 호출 가능
74+
75+
```python
76+
# conditional_breakpoint.py
77+
def compute_rmse(observed, ideal):
78+
...
79+
for got, wanted in zip(observed, ideal):
80+
err_2 = (got - wanted) ** 2
81+
if err_2 >= 1: # True인 경우에만 디버거를 실행함
82+
breakpoint()
83+
total_err_2 += err_2
84+
count += 1
85+
...
86+
result = compute_rmse(
87+
[1.8, 1.7, 3.2, 7],
88+
[2, 1.5, 3, 5])
89+
print(result)
90+
```
91+
92+
```python
93+
$ python3 conditional_breakpoint.py
94+
> conditional_breakpoint.py(14)compute_rmse()
95+
-> total_err_2 += err_2
96+
(Pdb) wanted
97+
5
98+
(Pdb) got
99+
7
100+
(Pdb) err_2
101+
4
102+
```
103+
104+
- 사후 디버깅(post-mortem debugging)
105+
- 예외 발생이나 프로그램 비정상 종류 이후 디버깅 가능
106+
- `python3 -m pdb -c continue [프로그램 경로]`
107+
- `pdb` 모듈이 프로그램 실행을 제어하게 할 수 있음
108+
- `continue` 명령은 `pdb`에게 프로그램을 즉시 시작하라고 명령
109+
- 프로그램 실행 후 문제가 발생하면 대화형 디버거로 제어 이전 그 시점부터 코드 상태 관찰 가능
110+
111+
```python
112+
# postmortem_breakpoint.py
113+
import math
114+
115+
# 평균 제곱근 오차(root# mean square error)를 구함
116+
def compute_rmse(observed, ideal):
117+
...
118+
119+
result = compute_rmse(
120+
[1.8, 1.7, 3.2, 7j], # 잘못된 입력
121+
[2, 1.5, 3, 5])
122+
print(result)
123+
```
124+
125+
```python
126+
$ python3 -m pdb -c continue postmortem_breakpoint.py
127+
Traceback (most recent call last):
128+
File ".../pdb.py", line 1697, in main
129+
pdb._runscript(mainpyfile)
130+
File ".../pdb.py", line 1566, in _runscript
131+
self.run(statement)
132+
File ".../bdb.py", line 585, in run
133+
exec(cmd, globals, locals)
134+
File "<string>", line 1, in <module>
135+
File "postmortem_breakpoint.py", line 4, in <module>
136+
import math
137+
File "postmortem_breakpoint.py", line 16, in compute_rmse
138+
rmse = math.sqrt(mean_err)
139+
TypeError: can't convert complex to float
140+
Uncaught exception. Entering post mortem debugging
141+
Running 'cont' or 'step' will restart the program
142+
> postmortem_breakpoint.py(16)compute_rmse()
143+
-> rmse = math.sqrt(mean_err)
144+
(Pdb) mean_err
145+
(-5.97-17.5j)
146+
```
147+
148+
- 프로그램을 실행하는 중에 예외가 발생했는데 처리되지 않은 경우
149+
- `pdb` 모듈의 `pm` 함수를 호출하면 사후 디버깅 사용 가능
150+
151+
```python
152+
$ python3
153+
>>> import my_module
154+
>>> my_module.compute_stddev([5])
155+
Traceback (most recent call last):
156+
File "<stdin>", line 1, in <module>
157+
File "my_module.py", line 17, in compute_stddev
158+
variance = compute_variance(data)
159+
File "my_module.py", line 13, in compute_variance
160+
variance = err_2_sum / (len(data) - 1)
161+
ZeroDivisionError: float division by zero
162+
>>> import pdb; pdb.pm()
163+
> my_module.py(13)compute_variance()
164+
-> variance = err_2_sum / (len(data) - 1)
165+
(Pdb) err_2_sum
166+
0.0
167+
(Pdb) len(data)
168+
1
169+
```

0 commit comments

Comments
 (0)