파이썬 강좌 – 반복문 ~ 비슷한 작업을 반복하기

  1. 프롤로그
  2. 개발 첫걸음
    1. 컴퓨터 구성요소 – 컴퓨터는 어떤 걸 할 수 있나?
    2. 개발과 관련된 용어
    3. 파이썬의 선택 – 왜 파이썬인가?
    4. 파이썬 설치 – Hello World 출력하기
    5. Visual Studio Code 의 편리한 기능
    6. REPL과 콘솔 창 – 파이썬 동작시키기
  3. 파이썬 기초
    1. 기초 입출력 – 소통하기
    2. 변수와 대입 – 기억하기
    3. 연산자 – 계산하기
    4. 조건문 – 분기를 만들기
    5. 반복문 – 비슷한 작업을 반복하기
    6. 반복문 코딩하기
    7. 변수와 리스트 – 비슷한 변수들을 묶기
    8. for, range – 리스트의 항목을 다루기
    9. 함수와 메소드의 호출 – 편리한 기능 이용하기
    10. 모듈 설치와 사용 – 유용한 기능 끌어다 쓰기
    11. 문자열 – 텍스트 다루기
  4. 파이썬 중급
    1. 함수를 직접 만들기 – 자주 쓰는 기능을 묶기
    2. 딕셔너리, 튜플, 세트 – 변수를 다양한 방법으로 묶기
    3. 클래스와 객체 – 변수를 사람으로 진화시키기
    1. 상속 – 클래스를 확장하기
    2. 정체성과 동질성 – 객체의 성질
    3. 특별 메소드와 연산자 – 파이썬의 내부 작동방식 이해하기
    4. 다양한 함수 인수 – 유연한 함수 만들기
    5. 슬라이싱 – 리스트 간편하게 접근하기
    6. 지능형 리스트(List Comprehension) – 리스트 갖고 놀기
    7. namedtuple - 데이터 묶음 손쉽게 만들기
    8. 조건 표현식 (Conditional Expression) - 간단한 분기 나타내기
    9. 코드 스타일 - 코드의 일관성 유지하기
    10. 명령문, 표현식 – 문법을 이루는 것들
    11. 본격적인 검색 해보기
  5. 파이썬 고급
    1. 일급 함수 다루기
    2. NotImplementedError와 NotImplemented
    3. 어노테이션 – 수월하게 프로그래밍하기
    1. 내장 함수 톺아보기
    2. 예외와 에러 – 예상치 못한 상황에 대응하기 (v0.1)
    3. 변수의 범위 – 이름 검색의 범위
  6. 파이썬 심화
    1. 시퀀스와 반복자 – 반복과 순회를 자유자재로 다루기
    2. 데코레이터 – 함수의 기능을 강화하기
    3. 프로퍼티
    4. 제너레이터
    5. async와 await
    6. 객체로서의 클래스 – 클래스를 동적으로 정의하기
  7. 파이썬 프로젝트 실습
    1. 원카드 게임 만들기 (1)
    2. 원카드 게임 만들기 (2)
    3. 원카드 게임 만들기 (3) (작성중)
    4. 턴제 자동 전투 게임 만들기 (작성중)
  8. 실전 (파이썬 외적인 것들)
    1. 정규표현식 – 문자열을 검색하고 치환하기 (작성중)
    2. 유니코드 – 컴퓨터에서 문자를 표기하는 방법
    3. html, css, 인터넷 – 자동화 첫 걸음 내딛기
    4. 네트워크 – 인터넷으로 통신하는 방법
    5. 문서 – 문맥을 읽어보기

때릴 수록 강력해지는 공격력

계속해서 새로운 개념을 배워나가고 있습니다. 이번 시간에는 반복문을 알아볼 겁니다. 역시나 예제로 시작합시다. 반복문의 필요성을 깨우쳐야 배울 힘이 나겠지요.

  • 슈퍼파워 게임회사는 플레이어가 훈련할 수 있는 샌드백을 만들고 있습니다.
  • 플레이어의 처음 공격력은 1밖에 되지 않지만 샌드백을 한 번 때릴 때마다 공격력이 1씩 증가합니다.
  • 샌드백은 공격받을 때마다 때린 사람의 공격력만큼 내구도가 낮아집니다.
  • 샌드백이 내구도가 0이 되면 샌드백은 부서집니다. (부서질 때에도 공격력은 성장합니다)
  • 샌드백의 내구도를 임의로 설정해보고 나서, 플레이어가 최종적으로 공격력이 몇인지 궁금합니다.

좋습니다. 샌드백의 내구도를 durability, 플레이어의 공격력을 attack이라 명명하고 코드를 짜 봅시다.

durability = int(input("샌드백의 내구도를 입력하세요 >> "))
attack = 1
durability -= attack
attack += 1
if durability <= 0:
    print("샌드백이 부서졌습니다! 최종 공격력은 " + str(attack) + "입니다.")
else:
    durability -= attack
    attack += 1
    if durability <= 0:
        print("샌드백이 부서졌습니다! 최종 공격력은 " + str(attack) + "입니다.")
    else:
        durability -= attack
        attack += 1
        if durability <= 0:
            print("샌드백이 부서졌습니다! 최종 공격력은 " + str(attack) + "입니다.")
        else:
            durability -= attack
            attack += 1
            if durability <= 0:
                print("샌드백이 부서졌습니다! 최종 공격력은 " + str(attack) + "입니다.")
            else:
                durability -= attack
                attack += 1
                if durability <= 0:
                    print("샌드백이 부서졌습니다! 최종 공격력은 " + str(attack) + "입니다.")
----- 1번째 실행 -----
샌드백의 내구도를 입력하세요 >> 13
샌드백이 부서졌습니다! 최종 힘은 6입니다.
----- 2번째 실행 -----
샌드백의 내구도를 입력하세요 >> 17

위 코드는 조건문을 이용하여 계속해서 durability를 attack 만큼 차감시키고 attack을 1씩 증가시키고 있습니다. durability은 최대 5번 차감될 수 있습니다. 왜냐하면 durability -= attack 부분이 5번 밖에 등장하지 않으니까요. 그래서 플레이어 또한 5번 밖에 성장하지 못합니다. 내구도가 13이라면 5회의 성장 안에 샌드백을 부술 수 있지만 내구도가 17이라면 성장 횟수가 부족하여 샌드백을 부수지 못합니다. (샌드백이 부숴졌다는 메세지가 뜨지 않습니다.)

오, 선생님! durability의 피해 값은 딱봐도 등차수열의 합이라서 durability = attack * (attack + 1) / 2 의 식을 풀어, 이차방정식을 만들어 양의 해를 구하기만 하면 끝날 문제 아닌가요?

어… 네 그렇게 생각 할 수도 있겠지만 매번 공식을 이용해 문제를 해결한다면, 상황이 바뀌었을 때 해당 공식을 매번 수정해야 하는 불편함이 있습니다. 지금은 직접 코드로 시뮬레이션한다고 생각하시면 좋을 듯 합니다.

여하튼 계속해서 반복하기에는 무리가 있습니다. 복사 붙여넣기는 만능이 아니지요. 만약 10000과 같은, 아주 큰 내구도를 집어넣는다면 도대체 얼마나 많이 복붙해야 할지 가늠도 오지 않습니다.

이러한 상황속에서 반복문은 빛나는 동아줄이 되어 우리를 구원해줄 수 있습니다.

durability = int(input("샌드백의 내구도를 입력하세요 >> "))
attack = 1
while durability > 0: ##a_1##
    durability -= attack
    attack += 1
print("샌드백이 부서졌습니다! 최종 공격력은 " + str(attack) + "입니다.")
----- 1번째 실행 -----
샌드백의 내구도를 입력하세요 >> 28
샌드백이 부서졌습니다! 최종 공격력은 8입니다.
----- 2번째 실행 -----
샌드백의 내구도를 입력하세요 >> 28371
샌드백이 부서졌습니다! 최종 공격력은 239입니다.

이게 무슨 일이죠? 코드의 양이 완전히 줄어들었습니다. 더군다나 28은 물론이고 28371 같은 아주 높은 숫자도 문제 없이 실행한다는 사실을 확인할 수 있습니다. 이만 팔천의 샌드백을 죽어라 때리고 때려서 공격력이 239까지 성장했다니! 그 사실을 바로 알 수 있다니. 정말 놀라울 따름입니다.

a_1(1.) 코드 설명

while durability > 0:

이 행이 이번 시간의 핵심입니다. while 이라는 새로운 키워드가 등장하였고, 그 바로 뒤에는 비교 연산자가 들어간 식이 들어갑니다. 행의 끝에 콜론(:)을 통해 새로운 블록을 시작한다고 말하는 것까지, 어찌 조건문과 굉장히 비슷하게 생겼습니다.

while의 동작 원리를 알려드리겠습니다. 뒤따르는 조건이 True 라면, 뒤따르는 블록을 실행합니다. 다시 돌아와 조건을 체크합니다. True라면 블록을 실행합니다. 다시 조건 체크 후 블록을 실행합니다. 계속, 무한 반복합니다. 조건이 False가 되어야 블록을 건너뛰고 다음으로 넘어갑니다.

이 while의 조건은 durability > 0 입니다. durability 변수이고 계속 우리가 차감시켜주고 있기 때문에 값이 계속해서 변합니다.


다음 코드는 바로 위 코드와 같지만, while 내부에 print 함수 하나를 추가하여 루프가 돌고 있는 시점에서 값이 어떻게 변화하는지 실시간으로 확인할 수 있도록 했습니다. 코드를 실행하여 결과를 확인해보세요.

durability = int(input("샌드백의 내구도를 입력하세요 >> "))
attack = 1
while durability > 0: 
    print("현재 공격력은 " + str(attack) + " 이며, 샌드백의 내구도는 " + str(durability) + " 입니다." )
    durability -= attack
    attack += 1
print("샌드백이 부서졌습니다! 최종 공격력은 " + str(attack) + "입니다.")

입력을 28371로 해보겠습니다.

(중략)
현재 공격력은 226 이며, 샌드백의 내구도는 2946 입니다.
현재 공격력은 227 이며, 샌드백의 내구도는 2720 입니다.
현재 공격력은 228 이며, 샌드백의 내구도는 2493 입니다.
현재 공격력은 229 이며, 샌드백의 내구도는 2265 입니다.
현재 공격력은 230 이며, 샌드백의 내구도는 2036 입니다.
현재 공격력은 231 이며, 샌드백의 내구도는 1806 입니다.
현재 공격력은 232 이며, 샌드백의 내구도는 1575 입니다.
현재 공격력은 233 이며, 샌드백의 내구도는 1343 입니다.
현재 공격력은 234 이며, 샌드백의 내구도는 1110 입니다.
현재 공격력은 235 이며, 샌드백의 내구도는 876 입니다.
현재 공격력은 236 이며, 샌드백의 내구도는 641 입니다.
현재 공격력은 237 이며, 샌드백의 내구도는 405 입니다.
현재 공격력은 238 이며, 샌드백의 내구도는 168 입니다.
샌드백이 부서졌습니다! 최종 공격력은 239입니다.

컴퓨터가 공식을 이용하거나 편법을 쓰지 않았다는 사실을 우리는 알 수 있습니다. 정말 순수하게 공격력을 1씩 올려가며 내구도를 닳게 하고 샌드백을 부서뜨립니다.


break

while은 조건을 검사해봤을 때 False가 나오는 순간 바로 반복문을 빠져나옵니다. 그렇다면 반복문을 빠져나올 방법은 조건에서 False가 나오도록 유도하는 방법 뿐일까요? 다행스럽게도 반복문을 빠져나올 수 있는 방법은 한 가지 더 있습니다. 바로 break를 이용하는 것입니다. 다음 예문을 참조해주세요.

durability = int(input("샌드백의 내구도를 입력하세요 >> "))
attack = 1
while True: 
    print("현재 공격력은 " + str(attack) + " 이며, 샌드백의 내구도는 " + str(durability) + " 입니다." )
    durability -= attack
    attack += 1
    if durability <= 0:
        break

print("샌드백이 부서졌습니다! 최종 공격력은 " + str(attack) + "입니다.")

break는 그냥 단독으로 break라고 씁니다. 파이썬 인터프리터가 break를 맞닥뜨리게 된다면, 그 즉시 while 블록 바깥으로 빠져나옵니다. while 조건과 상관없이, while문의 한복판에 있더라도 예외없이 동작합니다.

while True: 라는 뜻은, 이 while 블록을 영원히 반복하면서 실행시킬 것이라는 뜻입니다. True 값은 영원히 True 이므로 조건은 영원히 참이 되어 영원히 실행되게 되겠지요. 하지만 while 블록 내부에서 break를 사용한다면 이 루프문을 빠져나갈 수 있는 열쇠가 되어 프로그램의 흐름을 제어할 수 있게 됩니다.


개념 정리

개념 정리의 시간입니다. 정리할 개념은 생각보다 많이 없습니다.

  • while 은 조건이 True 이면 while 블록을 실행한다. 실행을 끝마치고 조건 검사부터 무한 반복한다.
  • while문의 조건이 한번이라도 False 가 되면 반복을 종료한다.
  • break를 통해 while 문 중간에 즉시 중단할 수 있다.
  • while 내부에 print 함수를 추가하여 반복이 진행되고 있는 시점에서 값이 어떻게 변화하는지 실시간으로 확인할 수 있다.

else

이제껏 잘 써왔던 예문을 살짝 수정하고자 합니다. 다음 예시는 공격력이 100까지 되었다면 단련이 충분하다 판단하고, 그만두면서 남은 내구도를 출력합니다. 그리고 100이 되기 전에 샌드백이 부셔졌다면 샌드백이 부서졌다고 출력합니다. 또한 둘 중 어느 경우라도 최종 공격력을 출력합니다.

durability = int(input("샌드백의 내구도를 입력하세요 >> "))
attack = 1
while durability > 0: 
    print("공격력: " + str(attack) + ", 내구도: " + str(durability))
    durability -= attack
    attack += 1
    if attack >= 100:
        print("충분히 단련했습니다. 남은 내구도는 " + str(durability) + "입니다.")
        break
else: ##b_1##
    print("샌드백이 부서졌습니다!")
print("최종 공격력은 " + str(attack) + "입니다.")

8000을 입력했습니다.

(중략)
공격력: 97, 내구도: 3344
공격력: 98, 내구도: 3247
공격력: 99, 내구도: 3149
충분히 단련했습니다. 남은 내구도는 3050입니다.
최종 공격력은 100입니다.

300을 입력했습니다.

(중략)
공격력: 22, 내구도: 69
공격력: 23, 내구도: 47
공격력: 24, 내구도: 24
샌드백이 부서졌습니다!
최종 공격력은 25입니다.

b_1(1.) 코드 설명

else가 등장했습니다. else는 앞서 조건문에서 등장한 바 있습니다. 하지만 이 else는 if와 짝지어지지 않고 while과 짝지어졌습니다. 이게 뜻하는 바는 무엇일까요?

while과 짝지어진 else는 if와 비슷하게 작동되는데요, while에 붙어 있는 조건식을 검사할 때, 이 값이 False가 나온다면 여기 else 블록을 실행하도록 합니다. 즉 조건에 의해 루프문을 빠져나왔을 때 else 블록이 실행되는 것이죠.

여기서 유의해야 할 점은 break를 통해 루프문을 빠져나왔을 때에는 이 else 블록이 실행되지 않는다는 점 입니다. else는 while에 붙어 있는 조건이 거짓일 때에만 실행되지, break와는 전혀 인연이 없다는 점을 꼭 명심해주세요.

보통의 다른 프로그래밍 언어에서는 else는 if와 같은 조건문에나 있지 while문 같은 반복문에는 잘 없습니다. 반복문에서 else를 사용할 수 있다는 점은 파이썬만의 특징이라고 볼 수 있습니다. 반복문에 붙어있는 else를 통해 break로 빠져나왔는지 그렇지 않은지 곧바로 체크할 수 있기 때문에 종종 쓰이곤 합니다.

위 프로그램에 대한 흐름도를 그리면 다음과 같습니다.

graph TD i1["durability = int(input('샌드백의 내구도를 입력하세요 >> '))<br>attack = 1"] i2["attack = 1"] i1-->i2-->c c{"durability > 0"} c-->|True|p p["print('공격력: ' + str(attack) + ', 내구도: ' + str(durability))<br> durability -= attack<br> attack += 1"] p-->c2 c2{"attack >= 100"} c2-->|True|br["print('충분히 단련했습니다. 남은 내구도는 ' + str(durability) + '입니다.')<br> break"]-->lp lp["print('최종 공격력은 ' + str(attack) + '입니다.')"] c2-->|False|c c-->|False|l["print('샌드백이 부서졌습니다!')"] l-->lp class i1,i2,c,p,br,c2,l,lp code

샌드백 최종 코드에 대한 순서도


continue

반복문 중에서 우리가 또 쓸 수 있는 용법이 있습니다. 뭐이리 많냐구요? 아니에요, 조금만 프로그래밍에 익숙해진다면 이런 기능을 찾게 될 거예요.

continue는 반복문 안에서 사용할 수 있는데요, 파이썬 인터프리터가 continue를 만나게 되면 즉시 다음 루프로 넘어갑니다. break는 실행되자마자 즉시 반복문 자체를 종료하는데, 기능이 조금 다르지요? 아래 예제는 위 예제와 기능상으로는 똑같습니다. 하지만 흐름은 조금 다르다는 걸 알게 될 거예요.

durability = int(input("샌드백의 내구도를 입력하세요 >> "))
attack = 1
while durability > 0: 
    print("공격력: " + str(attack) + ", 내구도: " + str(durability))
    durability -= attack
    attack += 1
    if attack < 100:
        continue

    print("충분히 단련했습니다. 남은 내구도는 " + str(durability) + "입니다.")
    break

else:
    print("샌드백이 부서졌습니다!")
print("최종 공격력은 " + str(attack) + "입니다.")

8000을 입력했습니다.

(중략)
공격력: 97, 내구도: 3344
공격력: 98, 내구도: 3247
공격력: 99, 내구도: 3149
충분히 단련했습니다. 남은 내구도는 3050입니다.
최종 공격력은 100입니다.

사실 위의 예제는 continue의 용법을 단지 설명하기 위해 인의적으로 집어넣었습니다. continue는 루프에서 어떤 조건에 맞지 않으면 더이상 이번 루프에서는 할 일이 없어서 다음번 루프로 넘기고자 할 때 유용합니다.


위 코드를 흐름도로 그리면 다음과 같습니다. 기존의 흐름과는 굉장히 유사합니다.

graph TD i1["durability = int(input('샌드백의 내구도를 입력하세요 >> '))<br>attack = 1"] i2["attack = 1"] i1-->i2-->c c{"durability > 0"} c-->|True|p p["print('공격력: ' + str(attack) + ', 내구도: ' + str(durability))<br> durability -= attack<br> attack += 1"] p-->c2 c2{"attack < 100"} c2-->|False|br["print('충분히 단련했습니다. 남은 내구도는 ' + str(durability) + '입니다.')<br> break"]-->lp lp["print('최종 공격력은 ' + str(attack) + '입니다.')"] c2-->|Ture|oo[continue]-->c c-->|False|l["print('샌드백이 부서졌습니다!')"] l-->lp

continue가 들어간 코드의 흐름


여담

이러한 순서놀이를 왜 하는 건지 이해가 되지 않는 분들도 있으실 겁니다. 이후에는 사실 for 반복문이라는, 더 직관적이고 간편한 방법도 있지요. 하지만 동작 원리를 바탕으로 실제 동작 과정을 머릿속으로 상상하는 추론력을 기르셔야 합니다. 그 방법은 while 이 참 좋다고 생각합니다. 간단한 원리이지만 아주 깊은 생각을 해야 실제 동작을 상상해낼 수 있기 때문입니다. 앞으로는 더 편한 함수, 더 편한 모듈을 사용해나가며 한결 수월하게 문제를 해결해나갈 것입니다만, 이러한 추론력이 뒷받침 되어주어야, 가지고 있는 도구를 비로소 효율적으로 활용할 수 있게 될 것입니다.


연습 문제

  • 반복문은 왜 사용하는가?
  • while의 조건이 무엇일때 while 블록이 실행되는가?
  • while 중간에서 즉시 루프를 마치려면 어떻게 해야 하는가?
  • 반복문이 진행중일 때 그 상황을 알고 싶다면 어떻게 해야 하는가?
  • 언제 break를 사용하는가?
  • while과 짝지어진 else는 무슨 역할인가?
  • while과 짝지어진 else는 언제 실행되지 않는가?
  • continue의 기능은 무엇인가?

프로그래밍 문제

반복문을 설계하는 방법을 익힌 후 본격적으로 프로그래밍 문제를 풀어보도록 하겠습니다.

  1. 프롤로그
  2. 개발 첫걸음
    1. 컴퓨터 구성요소 – 컴퓨터는 어떤 걸 할 수 있나?
    2. 개발과 관련된 용어
    3. 파이썬의 선택 – 왜 파이썬인가?
    4. 파이썬 설치 – Hello World 출력하기
    5. Visual Studio Code 의 편리한 기능
    6. REPL과 콘솔 창 – 파이썬 동작시키기
  3. 파이썬 기초
    1. 기초 입출력 – 소통하기
    2. 변수와 대입 – 기억하기
    3. 연산자 – 계산하기
    4. 조건문 – 분기를 만들기
    5. 반복문 – 비슷한 작업을 반복하기
    6. 반복문 코딩하기
    7. 변수와 리스트 – 비슷한 변수들을 묶기
    8. for, range – 리스트의 항목을 다루기
    9. 함수와 메소드의 호출 – 편리한 기능 이용하기
    10. 모듈 설치와 사용 – 유용한 기능 끌어다 쓰기
    11. 문자열 – 텍스트 다루기
  4. 파이썬 중급
    1. 함수를 직접 만들기 – 자주 쓰는 기능을 묶기
    2. 딕셔너리, 튜플, 세트 – 변수를 다양한 방법으로 묶기
    3. 클래스와 객체 – 변수를 사람으로 진화시키기
    1. 상속 – 클래스를 확장하기
    2. 정체성과 동질성 – 객체의 성질
    3. 특별 메소드와 연산자 – 파이썬의 내부 작동방식 이해하기
    4. 다양한 함수 인수 – 유연한 함수 만들기
    5. 슬라이싱 – 리스트 간편하게 접근하기
    6. 지능형 리스트(List Comprehension) – 리스트 갖고 놀기
    7. namedtuple - 데이터 묶음 손쉽게 만들기
    8. 조건 표현식 (Conditional Expression) - 간단한 분기 나타내기
    9. 코드 스타일 - 코드의 일관성 유지하기
    10. 명령문, 표현식 – 문법을 이루는 것들
    11. 본격적인 검색 해보기
  5. 파이썬 고급
    1. 일급 함수 다루기
    2. NotImplementedError와 NotImplemented
    3. 어노테이션 – 수월하게 프로그래밍하기
    1. 내장 함수 톺아보기
    2. 예외와 에러 – 예상치 못한 상황에 대응하기 (v0.1)
    3. 변수의 범위 – 이름 검색의 범위
  6. 파이썬 심화
    1. 시퀀스와 반복자 – 반복과 순회를 자유자재로 다루기
    2. 데코레이터 – 함수의 기능을 강화하기
    3. 프로퍼티
    4. 제너레이터
    5. async와 await
    6. 객체로서의 클래스 – 클래스를 동적으로 정의하기
  7. 파이썬 프로젝트 실습
    1. 원카드 게임 만들기 (1)
    2. 원카드 게임 만들기 (2)
    3. 원카드 게임 만들기 (3) (작성중)
    4. 턴제 자동 전투 게임 만들기 (작성중)
  8. 실전 (파이썬 외적인 것들)
    1. 정규표현식 – 문자열을 검색하고 치환하기 (작성중)
    2. 유니코드 – 컴퓨터에서 문자를 표기하는 방법
    3. html, css, 인터넷 – 자동화 첫 걸음 내딛기
    4. 네트워크 – 인터넷으로 통신하는 방법
    5. 문서 – 문맥을 읽어보기

One thought on “파이썬 강좌 – 반복문 ~ 비슷한 작업을 반복하기

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 항목은 *(으)로 표시합니다

Scroll to top