Notice
Recent Posts
Recent Comments
Link
«   2024/09   »
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
Tags
more
Archives
Today
Total
관리 메뉴

Nonamed Develog

[TIL][240701] UP & DOWN Game, Code Conventions, try/except, 다중 반복문 본문

WHAT I LEARN/TIL

[TIL][240701] UP & DOWN Game, Code Conventions, try/except, 다중 반복문

노네임드개발자 2024. 7. 1. 23:03

1. 입력한 값이 범위가 벗어날 경우 설정

어떤 문제가 있었나?
import random
random_number = random.randint(1, 100)

위의 random 입력값의 범위는 1~100 정수가 되는 것이 조건이다. 따라서 try/except을 이용하여 1~100 정수 외 숫자와 문자를 제외시켜보려 했다.

try:
    print("UP&DOWN! 1~100까지 숫자를 입력하세요!")
    number = int(input("숫자 입력: "))
    if number < random_number:
        print("UP")
    elif number > random_number:
        print("DOWN")
    else:
        print(f"딩동댕! 정답은 {random_number}입니다!")
        print(f"시도한 횟수: {count}")
        break
except ValueError:
    print("유효한 범위 내 숫자를 넣어주세요")

위와 같이 코드를 작성하고 실행시켜 봤는데, 문자열은 예외처리가 잘 되지만 1~100 외 숫자를 제외시키지 못했다.

무엇을 시도했나? 

except 뒤에 에러 종류에 따른 로직 처리 중 정수와 관련된 것을 있나 찾아봤다. 강의에서 없었던 여러 가지 로직을 찾아볼 수 있었다.

AssertionError: assert 문이 제대로 작동하지 않을 때 발생
IndexError: 참조 하려는 인덱스가 범위를 벗어날 때 발생
KeyError: 참조 하려는 키가 기존 키 집합에서 찾을 수 없을 때 발생
KeyboardInterrupt: 사용자가 인터럽트 키(Control + C, 혹은 Delete)를 누를 때 발생하며, 모든 Exception을 잡는 코드에 의해 인터프리터가 종료하는 것을 막지 못하도록 Exception 상위에 있는 BaseException을 직접 계승
MemoryError: 메모리가 부족하지만, 가비지 컬렉터가 일부 객체의 삭제를 함으로써 복구될 수 있는 경우 발생
NameError: 참조하는 지역, 전역 변수 혹은 함수, 클래스 등을 찾을 수 없을 때 발생
OSError: 시스템 함수가 시스템 관련 에러를 돌려줄 때 발생 (파일을 찾을 수 없거나, 디스크가 찼거나..)
OverflowError: 산술 연산의 결과가 너무 커서 표현할 수 없을 때, 혹은 정수 범위를 벗어났을 때 발생
RecursionError: 최대 재귀 깊이가 초과하였을 때 발생
TypeError: 연산이나 함수가 부적절한 데이터 타입의 객체에 적용되었을 때 발생
ValueError: 연산이나 함수가 부적절한 값을 가진 객체에 적용 되었을 때 발생
ZeroDivisionError: 나누기, 나머지 연산의 두 번째 인자가 0일 때 발생
어떻게 해결했는가?

try/except의 로직에서 정수를 걸러내는 로직은 없었기 때문에 if절에 조건을 추가하기로 했다.

random_numeber가 1~100의 입력값만 조건으로 하고 싶어 처음엔 아무 생각 없이 in을 사용했다.(sql 때문인가?)

number = int(input("숫자 입력: "))
if not number in random_number:
	print("유효한 범위 내 숫자를 넣어주세요")

결과는 TypeError: argument of type 'int' is not iterable

구글링해보니 iterable(리스트, 튜플)한 타입이 와야 하는데 int가 와서 생긴 에러라고 나왔다. 간편하게 비교 연산자를 사용하여 조건을 변경해 주었다.

try:
    print("UP&DOWN! 1~100까지 숫자를 입력하세요!")
    number = int(input("숫자 입력: "))
    if not 1 <= number <= 100:
        print("유효한 범위 내 숫자를 넣어주세요")
    elif number < random_number:
        print("UP")
    elif number > random_number:
        print("DOWN")
    else:
        print(f"딩동댕! 정답은 {random_number}입니다!")
        print(f"시도한 횟수: {count}")
        break
except ValueError:
    print("유효한 범위 내 숫자를 넣어주세요")

다음과 같이 1~100의 입력값만 들어갈 수 있게 설정 완료했다.

 

2. 다중 반복문 들여 쓰기

어떤 문제가 있었나?

while True 무한 반복을 통해서 UP&DONW 게임 한판은 할 수 있게 코드를 완성했지만 두 번 이상을 반복하는 코드를 완성하는 것에 시간을 많이 썼다. 처음 작성한 코드는 다음과 같다.

while True:
    count += 1
    try:
        # (생략) UP&DOWN 게임 조건문
        
            re_game = input("다시 하시겠습니까? (y/n): ")
            if re_game == "y":
                print(f"이전 게임 플레이어 최고 시도 횟수: {count}")
                continue
            elif re_game == "n":
                print("게임을 종료합니다")
                break
    except ValueError:
        print("유효한 범위 내 숫자를 넣어주세요")
무엇을 시도했나? 

들여 쓰기를 수정해 보고 continue를 이용하여 루프가 계속 반복되도록 코드를 작성해 봤지만 random_number가 변화가 없다는 것을 깨달았다. while True 반복문에 random_number를 추가해 봤다.

while True:
    random_number = random.randint(1, 100)
    count += 1
    try:
        # (생략) UP&DOWN 게임 조건문
        
            re_game = input("다시 하시겠습니까? (y/n): ")
            if re_game == "y":
                print(f"이전 게임 플레이어 최고 시도 횟수: {count}")
                continue
            elif re_game == "n":
                print("게임을 종료합니다")
                break
    except ValueError:
        print("유효한 범위 내 숫자를 넣어주세요")

하지만 무한 루프에서 random_number는 계속 바뀌어서 문제를 풀 수 없었다.(도대체 10보다 크고 11보다 작은 정수가 어딨 는데!!!!! print(random_number)로 숫자가 계속 바뀐다는 것을 파악)

어떻게 해결했는가?

결국 re_game에서 ramdom_number까지 어떻게 다시 루프를 돌리느냐가 포인트였다. 게임을 진행하는 코드에서는 random_number가 변하면 안 되기에 코드 밖에 있어야 하므로 루프에 루프를 씌우는 다중 반복문을 사용했다.

import random

while True:
    random_number = random.randint(1, 100)
    count = 0
    
    while True:
    # (생략) UP&DWON 게임 코드
    
    re_game = input("다시 하시겠습니까? (y/n): ")
    if re_game == "y":
        print(f"이전 게임 플레이어 최고 시도 횟수: {count}")
        continue
    elif re_game == "n":
        print("게임을 종료합니다")
        break
    else:
        print("y 또는 n을 입력하세요")
        re_game = input("다시 하시겠습니까? (y/n): ")

안쪽 무한 루프의 UP&DOWN 게임 코드가 돌아갈 때, 바깥쪽 루프의 random_numebr는 고정되고 새 게임을 시작하면 다시 바깥쪽 루프가 돌아가여 새 random_number를 받고 안쪽 루프인 UP&DOWN 게임 코드를 돌린다.

추가로 y/n을 제외한 다른 입력값이 들어갈 때 입력값을 다시 받을 수 있게 설정하고 마무리했다.

#완성 코드
import random

while True:
    random_number = random.randint(1, 100)
    count = 0

    while True:
        count += 1
        try:
            print("UP&DOWN! 1~100까지 숫자를 입력하세요!")
            number = int(input("숫자 입력: "))
            if not 1 <= number <= 100:
                print("유효한 범위 내 숫자를 넣어주세요")
            elif number < random_number:
                print("UP")
            elif number > random_number:
                print("DOWN")
            else:
                print(f"딩동댕! 정답은 {random_number}입니다!")
                print(f"시도한 횟수: {count}")
                break
        except ValueError:
            print("유효한 범위 내 숫자를 넣어주세요")

    re_game = input("다시 하시겠습니까? (y/n): ")
    if re_game == "y":
        print(f"이전 게임 플레이어 최고 시도 횟수: {count}")
        continue
    elif re_game == "n":
        print("게임을 종료합니다")
        break
    else:
        print("y 또는 n을 입력하세요")
        re_game = input("다시 하시겠습니까? (y/n): ")

 

새로 알게 된 점은 무엇인가?
  • in, not in 연산자의 결과는 bool 타입으로 리스트나 튜플 같은 iterable 한 데이터가 있으면 true 없으면 false이다. ( iterable: 반복가능한)
  • 추가 except의 예외 논리 (한번쯤 복습하기)
  • 무한 루프에 랜덤 요소를 넣으면 루프마다 랜덤 요소가 변화한다.
  • Cording conventions: 코드 작성에도 규칙이 있다.
    • 변수/함수를 네이밍 - snake 표기법: python_is_very_good
    • Class를 네이밍 - Paskal 표기법: PythonIsVeryGood (camel 표기법: pythonIsVeryGood)
    • 상수(절대 변하지 않는 수)는 대문자로 표기 (PIE = 3.14)
    • list를 표기할 때는 복수를 사용 (반복문에서 단/복수 구별 용이)
    • 함수를 네이밍 할 때는 역할 표기 (합 = sum)
무엇을 느꼈고 내일은 무엇을 할까?

파이썬으로 몰입했던 하루였다. 파이썬 심화 강의를 다 보고, 모르거나 애매하다고 할 수 있는 가려운 부분이 많이 해소되었다. 특히 서버 관련 쪽이 많이 도움이 되었다. 1번 개인 과제까지 마무리하는데 코드카타 문제를 풀거나 사전 캠프 때 파이썬 기본 강의를 들어서인지 기본적인 틀을 만들기엔 어렵지 않았다. (추가 도전 과제가 조금 힘들었지만)

 

내일은 2번 개인과제를 마무리하고, 밀린 코드카타 문제를 풀어보려 한다. 과제를 풀면서 느끼는 게 코드카타 문제로 알고리즘 적 사고를 많이 할 수 있었는데 요즘 다른 것에 집중한다고 조금 등한시했기 때문이다.