< 반복문 >
> while 반복문
while 반복문은 유사한 명령을 계속 실행하는 제어문이다.
일상생활에서 비슷한 작업을 반복하는 경우는 굉장히 흔한데 예를 들어 학생 5명의 성적을 처리한다면 다음과 같이 코드를 작성한다.
print("1 번 학생의 성적을 처리한다.")
print("2 번 학생의 성적을 처리한다.")
print("3 번 학생의 성적을 처리한다.")
print("4 번 학생의 성적을 처리한다.")
print("5 번 학생의 성적을 처리한다.")
* 이처럼 비슷한 명령을 처리할 때 반복문이 사용된다.
while 조건:
명령
* if 문과 형식이 유사하되 명령을 한 번만 실행하는 것이 아니라 조건이 만족하는 동안 계속 실행한다는 점이 다르다.
반복적으로 처리되는 명령을 루프(Loop) 라고 한다.
# while
student = 1
while student <= 5:
print(student, "번 학생의 성적을 처리한다.")
student += 1
* student 제어변수를 1로 initialize 하고, 이 값이 5 이하인 동안 출력문을 반복하면 다섯명의 학생 성적이 출력된다.
언젠가는 반복을 끝내야 하므로 루프에는 조건의 진위 여부를 바꾸는 명령이 반드시 포함되어 있어야 한다. (student += 1)
# sum 100
num = 1
sum = 0
while num <= 100:
sum += num
num += 1
print("sum =", sum)
# sum = 5050
* 1에서 100까지의 정수 합계를 구한다.
제어변수 num = 1, 합계를 누적할 변수 sum = 0 으로 초기화
그리고 while 루프로 진입하여 num이 100이하인 동안 sum에 num 값을 누적시킨다.
최초 루프에서 sum에 1 이 더해지고 num 을 증가시켜 2로 만든다.
100이 될 때까지 이 과정을 반복하므로 sum은 최종적으로 1 ~ 100의 정수 합계를 가진다.
다음 예제는 150 ~ 300의 모든 홀수 합을 구한다.
# sum odd
num = 151
sum = 0
while num <= 300:
sum += num
num += 2
print("sum =", sum)
#sum = 16875
> for 반복문
for 문은 컬렉션의 요소를 순서대로 반복하면서 루프의 명령을 실행하는 반복문이다.
컬렉션은 여러 개의 값을 모아 놓은 집합인데 리스트나 문자열이 대표적이다.
for 제어변수 in 컬렉션:
명령
리스트는 [ ] 괄호 안에 요소를 나열해 놓은 일정의 배열이며 for문은 요소를 하나씩 꺼내 제어 변수에 대입하여 루프에서 처리한다.
# for
for student in [1, 2, 3, 4, 5]:
print(student, "번 학생의 성적을 처리한다.")
* 리스트에는 1에서 5까지 학생의 번호가 저장되어 있다.
for 문은 이 리스트의 요소를 student 제어 변수에 하나씩 대입하면서 루프를 실행한다.
실행결과는 while 문과 같지만 제어 변수를 초기화하거나 증가시키는 문장이 없어 더 짧고 간단하다.
보통은 일정 범위의 리스트를 만들고 이 리스트 내의 요소를 반복하는데 이럴 때는 요소를 일일이 나열하기보다
range 명령으로 순차적으로 증가하는 리스트를 만든다.
range(시작, 끝, 증가값)
* 범위의 원칙에 의해 끝 값 자체는 포함되지 않는다.
for student in range(1, 6):
print(student, "번 학생의 성적을 처리한다.")
* range 명령을 사용하면 넓은 범위의 리스트를 손쉽게 생성할 수 있다.
# for sum
sum = 0
for num in range(1, 101):
sum += num
print("sum =", sum)
# sum = 5050
* 1 에서 100까지의 합계를 구하는 코드를 for 문으로 작성
# for sum2
sum = 0
for num in range(2, 101, 2):
sum += num
print("sum =", sum)
# sum = 2550
* 2 에서 100까지의 짝수 합계를 for 문으로 작성
while 문과 for 문은 서로 대체성과 장단점이 있기 때문에 용도에 따라 구분하여 사용한다.
for 문은 반복범위가 명확한 경우, while 문은 가변적인 경우에 주로 사용한다.
> 제어 변수의 활용
루프는 반복 횟수와 끝낼 시점을 결정하기 위해 제어 변수를 사용한다.
for a in range(5):
print("이 문장을 반복합니다.")
* 제어 변수를 꼭 사용해야 하는 것은 아니며 단순히 반복 횟수만 통제할 때는 읽지 않아도 상관없다.
루프는 개념은 쉽지만 응용이 어려워 많은 연습과 시행착오를 겪어야 하는 어려운 주제이다.
# ruler
for x in range(1, 51):
if (x % 10 == 0):
print("+", end="")
else:
print("-", end="")
---------+---------+---------+---------+---------+
if (x % 10):
print("-", end = "")
else:
print("+", end = "")
* 조건을 뒤집어 10으로 나누어 나머지가 있는 좌표에 " - " 를 출력하면 == 0 비교문을 생략할 수 있어 조금 더 간단해진다.
# ruler 2
for x in range(1, 6):
print("-" * 9, end="")
print("+", end="")
---------+---------+---------+---------+---------+
* 50번을 반복하는 대신 10칸을 하나의 반복 마디로 보고 " - " 문자 9개와 " + " 문자 1개를 출력하기를 다섯번 반복하는 방법도 있다.
# ruler 3
x = 1
while x <= 50:
if (x % 10):
print("-", end="")
else:
print("+", end="")
x += 1
---------+---------+---------+---------+---------+
* for 문은 제어 변수가 자동으로 변하는 데 비해 while 문은 그렇지 않으므로 루프 내부에서 반드시 x를 1 증가시켜야 한다.
# ruler 4
for x in range(1, 51):
if (x % 5 == 0):
print("+", end="")
else:
print("-", end="")
----+----+----+----+----+----+----+----+----+----+
# ruler 5
for x in range(1, 51):
if (x % 10 == 5):
print("+", end="")
else:
print("-", end="")
----+---------+---------+---------+---------+-----
코드에는 정답이라는 것은 없다.
굉장히 많은 해결책이 있으며 요구 사항대로 출력되면 다 정답이다.
다만 수많은 해결책 중에 가장 효율적이고 짧은 코드가 있을 뿐이다.
> break
반복문은 조건을 만족하는 동안 계속 실행하는 문장이라 일단 시작하면 끝까지 진행한다.하지만 중간에 어떤 이유로 반복을 중지하거나 현재 반복을 건너 뛰어야 할 경우가 있는데 이럴 때 흐름 제어문을 사용한다.
break 명령은 반복문을 끝낸다.어떤 이유로 더 이상 반복할 수 없거나 반복이 의미 없어졌다면 루프를 즉시 끝내고 다음 명령으로 이동한다.무조건 탈출 하는 것이 아니라 특정한 조건에 의해 탈출하므로 보통 if 문과 함께 사용한다.
# break
score = [92, 86, 68, 120, 56]
for s in score:
if (s < 0 or s > 100):
break
print(s)
print("성적 처리 끝")
92
86
68
성적 처리 끝
s = 92 #False
s = 86 #False
s = 68 #False
s = 120 #True -> break
> continue
break 명령을 루프를 탈출하는데 비해 continue 명령은 이번 루프 하나만 건너뛰고 나머지는 계속 수행한다.
현재 반복만 중지하고 선두로 돌아가 조건을 점검한 후 다음 번 반복을 계속 수행한다.
break와 마찬가지로 특정 조건일 때만 실행하므로 보통 if 문과 함께 사용한다.
# continue
score = [92, 86, 68, -1, 56]
for s in score:
if (s == -1):
continue
print(s)
print("성적 처리 끝")
92
86
68
56
성적 처리 끝
* 생략
break는 루프를 빠져나오는 것이고 (탈출)
continue는 하나만 건너뛰고 선두로 돌아가 루프를 계속 실행하는 것 (생략)
두 명령은 while 문에도 똑같이 적용되며 조건에 따라 루프의 계속 실행 여부를 통제한다.
< 루프의 활용 >
> 이중 루프
루프 안에 들어가는 명령의 종류에는 제약이 없어 또 다른 루프가 들어갈 수도 있다.
루프끼리 중첩된 것을 이중 루프라고 한다.
# multiplication table_ for
for x in range(2, 10):
print(x, "단")
for y in range(1, 10):
print(x, "*", y, "=", x * y)
print()
* for 문을 활용한 2단부터 9단까지 곱하는 구구단을 생성하는 이중 루프 코드
# multiplication table_ while
x = 2
while x <= 9:
y = 2
print(x, "단")
while y <= 9:
print(x, "*", y, "=", x * y)
y += 1
x += 1
print()
* while 문을 활용한 구구단을 생성하는 이중 루프 코드
# triangle
for y in range(1, 10):
for x in range(y):
print("*", end="")
print()
*
**
***
****
*****
******
*******
********
*********
* 이중 루프를 사용한 삼각형 별 찍기
y 가 1에서 9까지 변하며 루프 내부에서 x 루프를 돌린다.
각 x 루프에서 * 문자를 출력하되 x 루프의 반복 횟수는 y 만큼이다.
그래서 첫 줄에 * 하나를 출력하고 개행, 다음 줄에 * 두개를 출력하고 개행하는 식으로 개수가 계속 늘어나 전체적으로 삼각형이 그려진다.
이 예제의 핵심은 안쪽 루프에서 바깥쪽 루프의 제어 변수를 참조한다는 점이다. 루프 내부에서 제어 변수는 언제든지 참조 할 수 있다.
x 루프의 반복 횟수를 바깥쪽의 y제어 변수값으로 결정하므로 각 행에 출력되는 * 문자의 개수가 1에서 9까지 점점 늘어난다.
> 중첩 루프
이번 절에서는 중첩 루프(nested loop)에 대해 알아보겠습니다.
여기서 '루프' 라는 용어는 반복을 의미하고 '중첩' 이라는 것은 여러 개가 겹치는 것을 의미합니다.
즉, 반복문 여러개가 겹쳐 있는 구조를 중첩 루프라고 합니다.
보통 두 개의 반복문이 겹쳐 있는 '이중 루프'와 세개의 반복문이 겹쳐 있는 '삼중 루프'를 가장 많이 사용합니다.
다음은 반복문 두 개가 겹쳐 있는 '이중 루프'의 예입니다.
반복문은 for 키워드를 사용했고 for 문 내부에서 조건을 만족할 때 수행되는 문장에는 pass 키워드를 사용했습니다.
참고로 파이썬의 pass 키워드는 아무것도 수행하지 않음을 의미합니다.
for i in [1, 2, 3, 4]:
for j in [1, 2, 3, 4]:
pass
파이썬 반복문에는 실행될 문장이 최소한 하나라도 있어야 문법 오류가 나지 않으므로 pass를 사용해 문법 오류가 발생하는 것을 방지하는 것입니다.
물론 pass 대신 print("") 같은 구문을 넣어도 프로그램의 동작을 간단히 테스트해볼 수도 있습니다.
그렇다면 어떤 경우에 두 개의 반복문을 겹쳐서 사용하는 것일까요?
아래 그림은 아파트의 각 세대를 간단히 표시해 본 것입니다.
1 층에는 101호, 102호, 103호, 104호가 있고
2층에는 201호, 202호, 203호, 204호가 있습니다.
지금까지 반복문으로는 101호, 102호, 103호, 104호에 대해 반복적인 일을 수행할 수 있습니다.
그런데 그림과 같이 1층에만 세대가 있는 것이 아니라 2층, 3층, 4층에도 각 세대가 있습니다.
우리가 자주 사용하는 엑셀도 데이터가 그림과 같은 형태로 저장되는데
이러한 구조를 2차원 데이터라고 표현합니다.
이러한 2차원 데이터를 다룰 때 필요한 것이 바로 이중 루프입니다.
401 | 402 | 403 | 404 |
301 | 302 | 303 | 304 |
201 | 202 | 203 | 204 |
101 | 102 | 103 | 104 |
- 2차원 데이터의 표현
각 세대에 대해 신문을 자동으로 배달하는 로봇을 만든다고 가정해 봅시다.
지금까지 배운 반복문을 사용한다면 다음과 같이 로봇에 프로그래밍해야 할 것입니다.
1층에 가서 1층의 각 세대에 신문 배달
2층에 가서 2층의 각 세대에 신문 배달
3층에 가서 3층의 각 세대에 신문 배달
4층에 가서 4층의 각 세대에 신문 배달
1층에 가서 각 세대에 신문을 배달하는 것을 파이썬의 반복문을 사용하면 다음과 같이 표현할 수 있습니다.
이 코드를 복사해서 리스트의 값만 바꿔주면 2층, 3층, 4층에도 신문을 배달 할 수 있습니다.
그러나 이 방식은 각 층에 있는 세대에 대해서는 반복문을 사용했지만 층별로는 여전히 반복문을 사용하지 못했기 때문에
코드가 중복되고 길어진다는 단점이 있습니다.
for i in [101, 102, 103, 104]:
print("Newspaper delivery: ", i)
Newspaper delivery: 101
Newspaper delivery: 102
Newspaper delivery: 103
Newspaper delivery: 104
이번에는 이중 루프를 이용해 코드를 작성해 보겠습니다.
이를 위해서는 먼저 위 그림과 같은 2차원 데이터를 파이썬의 2차원 리스트로 표현해야 합니다.
이전에 배운 1차원 리스트는 [ ] 기호 사이에 데이터가 쉼표로 구분되어 저장되는 형태였습니다.
2차원 리스트는 리스트 안에 정수열, 문자열, 실수형과 같은 데이터가 존재하는 것이 아니라 리스트 타입이 존재하는 구조를 의미합니다.
예를 들어 위 그림과 같은 테이블은 다음과 같이 2차원 리스트로 표현할 수 있습니다.
>>> apart = [[101, 102, 103, 104],[201, 202, 203, 204],[301, 302, 303, 304], [401, 402, 403, 404]]
2차원 리스트도 1차원 리스트와 마찬가지로 인덱싱할 수 있습니다.
aprt[0]으로 apart 리스트의 첫 번째 원소에 접근할 수 있는데, 리스트의 첫 번째 원소 역시 리스트입니다.
다음 코드를 보면 2차원 리스트에 대한 인덱싱을 통한 각 층의 세대 정보가 저장된 리스트에 접근 할 수 있습니다.
apart[0]에 위치한 값이 정말로 리스트 타입인지 확인하기 위해 type 함수를 사용해 보면 정말로 리스트 타입인 것을 확인할 수 있습니다.
>>> apart[0]
[101, 102, 103, 104]
>>> apart[1]
[201, 202, 203, 204]
>>> apart[2]
[301, 302, 302, 303]
>>> apart[3]
[401, 402, 403, 404]
>>> type(apart[0])
<class 'list'>
>>>
2차원 구조의 데이터를 2차원 리스트로 표현했으니 이중 루프를 이용해 신문 배달을 해보겠습니다.
다음 코드를 보면 먼저 바깥쪽 for문을 통해 각 층에 대한 리스트를 구합니다.
바깥쪽 for문이 동작하는 동안 floor 변수는 [101, 102, 103, 104], [201, 202, 203, 204], [301, 302, 303, 304], [401, 402, 403, 404] 라는
리스트를 순서대로 바인딩하게 됩니다.
이를 그림으로 나타내면 아래와 같습니다.
바깥쪽 for문이 첫번째로 실행될 때 floor 변수가 2차원 리스트의 첫번째 원소인 [101, 102, 103, 104] 리스트를 바인딩하는 것을 나타냅니다.
>>> for floor in apart:
for room in floor:
print("Newspaper delivery: ", room)
Newspaper delivery: 101
Newspaper delivery: 102
Newspaper delivery: 103
Newspaper delivery: 104
Newspaper delivery: 201
Newspaper delivery: 202
Newspaper delivery: 203
Newspaper delivery: 204
Newspaper delivery: 301
Newspaper delivery: 302
Newspaper delivery: 302
Newspaper delivery: 303
Newspaper delivery: 401
Newspaper delivery: 402
Newspaper delivery: 403
Newspaper delivery: 404
>>>
for 문은 반복문이 실행될 때 for 문에서 들여쓰기된 문장을 실행하는데,
이중 루프에서는 for 문 안쪽에서 실행할 문장이 역시 또 다른 for 문입니다.
따라서 "for room in floor" 라는 안쪽 for 문이 실행됩니다.
바깥쪽 for 문이 처음 실행될 때 floor 변수는 [101, 102, 103, 104]를 바인딩하고 있으므로
안쪽 for 문이 동작하면 room 변수는 101, 102, 103, 104 라는 값을 순서대로 바인딩하게 될 것 입니다.
안쪽 for 문이 처음으로 실행될 때 room은 101 이라는 값을 바인딩한 상태로 for 문 안쪽의 문장을 실행하게 됩니다.
따라서 화면에는 101호에 대한 신문 배달이 출력될 것입니다.
그 다음 역시 안쪽 for문에 대한 신문 배달이 이뤄지고, 이러한 작업은 104호까지 계속됩니다.
104호까지 신문 배달이 끝나면 안쪽 for 문은 모든 수행이 완료됐기 때문에 바깥쪽 for 문 기준으로는 두번째 반복이 시작됩니다.
따라서 floor 변수가 이번에는 [201, 202, 203, 204] 를 바인딩한 상태에서 다시 안쪽 for 문을 수행하게 됩니다.
따라서 room 이라는 변수는 이번에는 201, 202, 203, 204를 차례대로 바인딩하게 되며 이 값이 순서대로 출력됩니다.
> 무한 루프
무한 루프는 반복 횟수를 정하지 않고 무한히 반복하는 루프이다.
while 문으로 작성하며 for 문으로는 무한 루프를 만들 수 없다.
while True:
명령
if 탈출조건 : break
* while 문의 조건식에 상수 True 를 적어 두면 반복 조건이 항상 참이므로 이 루프는 무한히 반복된다.
진짜 무한히 반복해서는 안되므로 루프 중간에 반드시 break 명령을 두어 적당한 조건이 되었을 때 루프를 끝내야 한다.
# infinite
print("3 + 4 = ?")
while True:
a = int(input("정답을 입력하시오: "))
if (a == 7):
break
print("참 잘했어요")
* 사용자가 정답을 입력할 때까지 반복하되 문제는 언제 정답을 입력할지 미리 알수 없다는 점이다.
그래서 형식적으로는 무한 루프를 구성하고 정답을 입력할 때까지 계속 반복한다.
> 범위의 원칙
일상생활에서 범위를 칭할 때는 항상 끝 부분을 포함한다.
그러나 컴퓨터에서 범위를 칭할 때는 끝 요소를 제외하고 그 직전까지만 포함한다.
range(1, 10)은 1 ~ 10 이 아닌 1 ~ 9 범위의 리스트를 만든다.
컴퓨터는 숫자를 항상 0부터 시작한다.
기준점(Base)에서의 상대적인 거리를 오프셋이라고 하는데 첫 요소의 오프셋이 0부터 시작해야 계산이 빠르고 자연스러워진다.
'Language > Python' 카테고리의 다른 글
Python_08. String management (0) | 2022.07.31 |
---|---|
Python_07. Function (0) | 2022.07.31 |
Python_05. Conditional Statement (0) | 2022.07.27 |
Python_04. Operator (0) | 2022.07.27 |
Python_03. Type (0) | 2022.07.25 |