티스토리 뷰
6.13.2 탑-다운(보텀-업) 구현 (Top-Down and/or Bottom-Up Implementation)
이전 포스트 함수 추상화와 단계적 개선(1) 을 보려면 ●클릭하기●
*printCalendar 도식화
- 앞서 분할-정복으로 문제를 세분화 시켰다면, 이제는 그 문제들을 해결할 코드를 구현 할 차례다.
- 일반적으로, 서브 문제(subproblem, 분할-정복 시 생겼던 하위 문제들)들은 함수를 구현한 코드에 상응하지만, 일부는 불필요할 정도로 단순하다.
- 우리는 어떤 모듈로 함수를 구현 할 지, 그리고 어떻게 다른 함수들과 조합할 지 결정해야 한다.
- 이전 포스트 부터 배웠던 방법을 토대로 코드를 구현한다면, 코드를 해석할 때 훨씬 읽기 쉬워진다.
- 이전 포스트에서 예로 들었던 printCalender 프로그램에서의 서브문제(subproblem)였던 readInput은 메인 함수(main)에서 바로 구현이 가능하다.
- 우리는 탑-다운(top-down) 이나 보텀-업(bottom-up) 방식으로 접근이 가능하다.
- 탑-다운 접근은 한번에 하나 씩 함수를 위에서 아래로 구현하는 것이다.
- 간단하지만 아직 완성되지 않은 함수를 의미하는 스텁(stub)은 지금 만들고 있는 함수를 위해 사용되며, 프로그램의 프레임 워크를 빠르게 구현 할 수 있게 해준다.
- 예를 들어, 먼저 main 함수를 구현할 때, printMonth 함수를 아래와 같이 만드는 것이 스텁(stub)이다.
* 스텁 예시
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 |
#printMonth 함수의 스텁
def printMonth(year, month):
print(year, month)
#printMonthTitle 함수 스텁
def printMonthTitle(year, month):
print("printMonthtitle")
#getMonthBody 함수 스텁
def getMonthBody(year, month):
print("getMonthBody")
#getMonthName 함수 스텁
def getMonthName(month) :
print("getMonthName")
#getStartDay 함수 스텁
def getStartDay(year, month):
print("getStartDay")
# getTotalNumberOfDays 함수 스텁
def getTotalNumberOfDays(year, month):
print("getTotalNumberOfdays")
# getNumberOfDaysInMonth함수 스텁
def getNumberOfdaysInMonth(year, month):
print("getNumberOfDayInMonth")
# isLeapYear 함수 스텁
def isLeapYear(year):
print("isLeapYear")
def main():
#연, 월 입력
year = eval(input("연도를 입력하세요. (예, 2001): "))
month = eval(input("월에 해당하는 숫자를 입력하세요(1-12)"))
#해당 연도의 월 출력
printMonth(year, month)
main() |
cs |
- 위와 같이 스텁(stub) 함수를 작성하면 main함수를 먼저 간단히 테스트해 볼 수 있고, 에러를 고쳐 main함수를 다 완성한 뒤 안정적으로 printMonth함수를 구현 할 수 있다.
- 보텀-업(bottom-up)은 아래에서 위로 한번에 하나씩 함수를 구현하는 것이다.
- 둘 중 어떤 방법을 써도 괜찮으며, 모두 점진적으로 함수를 수행하고 프로그래밍 오류를 분리하고 디버깅을 쉽게 할 수 있도록 도와준다.
6.13.3 구현 세부 사항(Implementation Details)
- 위 접근 방법을 토대로 이제 코드를 구현하면 된다.
- getTotalNumoberOfDays(year, month) 함수를 예로
■ 1, 3, 5, 7, 8, 10, 12월은 31일을 가지고 있다.
■ 4, 6, 9, 11월은 30일을 가지고 있다.
■ 2월은 평년에는 28일, 윤년에는 29일을 가진다.
- 이런 방식으로 각 함수마다 기능들을 특징화시켜 코드를 구현하면 된다.
*printCalendar 완성 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116 |
# 주어진 연도와 월에 대한 달력을 출력한다.
def printMonth(year, month):
# 달력 머리행을 출력한다.
printMonthTitle(year, month)
# 달력의 몸체를 출력한다.
printMonthBody(year, month)
# 달력의 제목을 출력한다. 예, May 1999
def printMonthTitle(year, month):
print(" ", getMonthName(month), " ", year)
print("-----------------------------")
print(" Sun Mon Tue Wed Thu Fri Sat")
# 달력의 몸체를 출력한다.
def printMonthBody(year, month):
# 주어진 월의 첫 번째 일에 대한 시작 요일을 구한다.
startDay = getStartDay(year, month)
# 월의 일수를 구한다.
numberOfDaysInMonth = getNumberOfDaysInMonth(year, month)
# 월의 첫째 날 앞에 공백을 삽입한다.
i = 0
for i in range(startDay):
print(" ", end = "")
for i in range(1, numberOfDaysInMonth + 1):
print(format(i, '4d'), end = "")
if (i + startDay) % 7 == 0:
print() # 새로운 행으로 이동한다.
# 월에 대한 영문 이름을 가져온다.
def getMonthName(month):
if month == 1:
monthName = "January"
elif month == 2:
monthName = "February"
elif month == 3:
monthName = "March"
elif month == 4:
monthName = "April"
elif month == 5:
monthName = "May"
elif month == 6:
monthName = "June"
elif month == 7:
monthName = "July"
elif month == 8:
monthName = "August"
elif month == 9:
monthName = "September"
elif month == 10:
monthName = "October"
elif month == 11:
monthName = "November"
else:
monthName = "December"
return monthName
# 주어진 년/월/일의 시작 요일을 구한다.
def getStartDay(year, month):
START_DAY_FOR_JAN_1_1800 = 3
# 1800년 1월 1일부터 주어진 년/월/1까지 총 일수를 구한다.
totalNumberOfDays = getTotalNumberOfDays(year, month)
# 주어진 년/월/1의 시작 요일을 반환한다.
return (totalNumberOfDays + START_DAY_FOR_JAN_1_1800) % 7
# 1800년 1월 1일부터 총 일수를 계산한다.
def getTotalNumberOfDays(year, month):
total = 0
# 1800년부터 입력된 년도의 1월 1일까지 모든 일수를 계산한다.
for i in range(1800, year):
if isLeapYear(i):
total = total + 366
else:
total = total + 365
# 1월부터 입력된 월의 이전 월까지 모든 일수를 더한다.
for i in range(1, month):
total = total + getNumberOfDaysInMonth(year, i)
return total
# 해당 월의 총 일수를 구한다.
def getNumberOfDaysInMonth(year, month):
if (month == 1 or month == 3 or month == 5 or month == 7 or
month == 8 or month == 10 or month == 12):
return 31
if month == 4 or month == 6 or month == 9 or month == 11:
return 30
if month == 2:
return 29 if isLeapYear(year) else 28
return 0 # 잘못된 월 입력일 경우
# 입력된 연도가 윤년인지 결정한다.
def isLeapYear(year):
return year % 400 == 0 or (year % 4 == 0 and year % 100 != 0)
def main():
# 사용자로부터 년도와 월을 입력받는다.
year = eval(input("연도를 입력하세요(예, 2001): "))
month = eval(input(("월에 해당하는 숫자를 입력하세요(1-12): ")))
# 입력 연도와 월에 대한 달력을 출력한다.
printMonth(year, month)
main() # main 함수를 호출한다. |
cs |
6.13.4 단계적 개선의 이점(Benefits of Stepwise Refinement)
- 단계적 개선 접근법은 큰 문제점(a large problem)을 작은 문제(subproblem)로 바꾸는 것이다.
- 코드 작성, 재사용, 디버그, 테스트, 유지 보수 등에 유용하다.
* 단계적 개선의 이점
■ 프로그램 간소화
printCalendar 프로그램처럼 길이가 긴 프로그램, 또는 대형 프로그램을 작성할 때 유용하다. 큰 문제를 작은 문제로 간소화 시킨 후 프로그램을 작성하는 것이기 때문에, 전체 프로그램을 작성하기도, 나중에 해석하기도 쉬워진다.
■ 함수 재사용
단계적 개선법은 코드의 재사용을 촉진시킨다. 예를 들어 isLeapYear 함수는 getTotalNumberOfDays와 getNumberOfDasInMonth 함수에서 호출해 사용하는 함수이다. 코드의 중복을 줄일 수 있다.
■ 개발 과정, 디버깅 과정, 테스트 과정을 줄일 수 있다.
탑-다운이나 보텀-업 접근을 이용하여 디버깅 과정과 테스트 과정 등을 줄일 수 있다. 지금 당장에는 작은 프로그램을 구현하기 때문에 효과를 잘 느끼지 못할 지라도, 나중에 대형 프로그램을 만들 때는 확실히 시간과 디버깅 횟수 낭비를 줄일 수 있다.
■ 더 효율적인 팀워크를 제공한다.
단계적 개선은 큰 문제를 작은 문제로 나누는 과정이기 때문에, 이 나뉘어진 작은 문제들을 프로그래머들에게 할당하기 매우 쉬워진다.
참고 문헌 : Introduction to Programming Using Python / Y.DANIEL LIANG
※
본 게시물은 개인적인 용도로 작성된 게시물입니다. 이후 포트폴리오로 사용될 정리 자료이니 불펌과 무단도용은 하지 말아주시고 개인 공부 목적으로만 이용해주시기 바랍니다.
교재 영어 원서를 직접 번역하여 정리한 게시물이므로 일부 오타, 의역이 존재할 수 있습니다. 틀린 부분이 있다면 댓글로 알려주시면 감사하겠습니다.
※
'파이썬 > 이론' 카테고리의 다른 글
[파이썬]생성자(Constructor), 객체 멤버 접근, self 매개 변수 (1) | 2017.08.01 |
---|---|
[파이썬]객체와 클래스(Objects and Classes),생성자(initializer) (2) | 2017.07.31 |
[파이썬]랜덤 ASCII 문자 생성, 함수 추상화와 단계적 개선(1) (0) | 2017.07.28 |
[파이썬]변수의 범위, 기본 인자, 다중값 반환, 10진수를 16진수로 변환 (0) | 2017.07.27 |
[파이썬]레퍼런스값에 의한 인자 전달, 모듈화 (0) | 2017.07.26 |
- Total
- Today
- Yesterday
- 자바
- 파이썬 단계적 개선
- 파이썬 선택문
- 파이썬 진수 변환
- 버츄어박스
- 파이썬 문자열
- 백준 11501
- 파이썬 for
- css 그리드
- 파이썬 터틀
- 파이썬 if문
- 자바스크립트 자료구조
- 파이썬 함수
- 자바스크립트 그래프
- 파이썬
- 자바 에센셜 실습문제
- 웹
- 백준 1874
- css 박스
- 자료구조
- css
- 파이썬 객체
- 파이썬 예제
- 백준 10451
- 파이썬 리스트
- 백준
- 파이썬 연산자
- 파이썬 while
- 명품 c++ 실습
- 파이썬 클래스
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |