[TIL #3] 코드컨벤션과 첫 알고리즘

안떽왕·2023년 3월 21일
1

Today I Learned

목록 보기
3/76

코드컨벤션

오늘 강의로 코드컨벤션에 대해 알게 되었고 파이썬의 경우 함수는 Snake 표기법, 클래스는 Pascal 표기법을 쓴다는 것을 알게 되었다.

  • Snake 표기법: very_nice_day 처럼 '언더바'로 띄어쓰기를 대체하는 표기법

  • Pascal 표기법: VeryNiceDay 처럼 대문자로 각 단어를 구별하는 표기법

이후 PEP8 패키지를 설치해 자동으로 코드가 정렬되는 설정을 따라가고 있었는데 문제가 발생했다.

문제상황

  1. VScode 설정에서 Python > Formatting: Provider 설정을 autoPEP8로 설정 해주고
  2. Format On Save 기능을 체크해 주었다.(저장 시 자동으로 PEP8에 맞춰주는 기능)

여기까지 진행한 후 파이썬 파일로 돌아와 저장을 누르면 autopep8이 저장되지 않았다는 문구의 경고 창이 올라오며 설치를 진행해야 하는데 나는 이미 설치가 되어있었는지 경고 창이 올라오지 않아 개별로 설치해 주고자 하였다.

해결시도

강의 영상을 짧게 짧게 멈춰가며 보니 경로와 명령어가 venv\Scripts>python.exe -m pip install -U autopep8 로 적히는 것을 확인할 수 있었다.

터미널에서 해당 경로로 이동한 뒤 해당 명령어를 입력하고 설치까지 완료하고 파이썬 파일로 돌아와 저장을 눌러보았으나 변화는 생기지 않았다.

해결

곰곰이 생각을 해봤는데
다른 패키지를 받을 때도 별도로 이동하지 않고 해당 프로젝트 폴더 경로에서 설치를 했는데 autopep8은 왜 경로가 저렇게 될까?
혹시 기존 폴더에 설치를 해도 자동으로 경로를 설정해 알아서 설치가 되는 게 아닐까? 라는 생각을 하게 되었다.

그래서 프로젝트 폴더 경로로 돌아와 pip install autopep8 명령어를 입력하니 Requirement already satisfied 요구사항이 이미 충족되어 있다는 문구가 출력되고 혹시 하는 마음에 파이썬 파일로 돌아가 저장을 해보니 위에서 autopep8로 설정할 것이냐는 창이 내려오고 확인을 누르니 정상적으로 저장 시 autopep8이 적용될 수 있었다.

알게된 점

패키지마다 다르겠지만 패키지를 설치할 때는 프로젝트 폴더에서 설치해 볼 것

사실 autopep8 적용 창이 나왔을 때 침착하게 이게 어떤 창인지 살펴보고 기록을 했어야 했는데 너무 기쁘고 반가운 나머지 확인도 안 하고 적용을 눌러버려 어떤 설정 창이였는지 알 수 없는 게 너무 마음이 아프다...

다음에 유사한 상황이 나온다면 당황하지 말고 침착하게 먼저 기록으로 남겨놓자는 생각을 가지게 되었다.

알고리즘

부록으로 나눠준 PYTHON HAND BOOK안에 있는 알고리즘 문제를 풀어 보았다.
https://nmdkims-organization.gitbook.io/python-hand-book/day1./3.-mission2

문제설명

수포자는 수학을 포기한 사람의 준말입니다. 수포자 삼인방은 모의고사에 수학 문제를 전부 찍으려 합니다. 수포자는 1번 문제부터 마지막 문제까지 다음과 같이 찍습니다.

  • 1번 수포자가 찍는 방식: 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, ...
  • 2번 수포자가 찍는 방식: 2, 1, 2, 3, 2, 4, 2, 5, 2, 1, 2, 3, 2, 4, 2, 5, ...
  • 3번 수포자가 찍는 방식: 3, 3, 1, 1, 2, 2, 4, 4, 5, 5, 3, 3, 1, 1, 2, 2, 4, 4, 5, 5, ...

1번 문제부터 마지막 문제까지의 정답이 순서대로 들은 배열 answers가 주어졌을 때, 가장 많은 문제를 맞힌 사람이 누구인지 배열에 담아 return 하도록 solution 함수를 작성해주세요.

나의 생각

맨 처음 이 설명을 보았을 때 무슨 문제였는지 이해조차 못 했다.. 심지어 밑에 있는 힌트들을 보고도 무슨 말인지 이해를 못 했는데 문제를 해결 하고 나서 보니 이해가 조금 될 것 같다.

이해를 못 했던 부분은 가장 문제를 많이 맞춘 사람을 선정해야 하는데 그 문제에 답안이라 하는 answers는 대체 어떤 값인가였다.

곰곰이 생각해 보니 이 문제는 답을 도출하는 문제가 아니라 함수를 작성하는 문제라는 것을 깨닫고 나서야 비로소 생각했다. 정답은 제한 조건에만 만족된다면 어떤 것이 들어가도 상관이 없는 함수를 작성하라는걸....

제한조건

  • 시험은 최대 10,000 문제로 구성되어있습니다.
  • 문제의 정답은 1, 2, 3, 4, 5중 하나입니다.
  • 가장 높은 점수를 받은 사람이 여럿일 경우, return하는 값을 오름차순 정렬해주세요.

나의생각

하... 제한조건... 문제 다 풀고 나서야 3번째 조건을 확인했다... 다 풀고 혼자서 내 입맛에 맞게 개조해버렸는데 TIL 작성하려고 보니 "동점자는 오름차순 정리할 것" 을 확인했다.

풀이

import random

question_answers = []

def solution(answers):
    answer = []

    cnt_one = 0
    cnt_two = 0
    cnt_three = 0

    one = [1, 2, 3, 4, 5]
    two = [2, 1, 2, 3, 2, 4, 2, 5]
    three = [3, 3, 1, 1, 2, 2, 4, 4, 5, 5]

    rank = {}

    for i, ans in enumerate(answers):
        if one[i % 5] == ans:
            cnt_one += 1
        if two[i % 8] == ans:
            cnt_two += 1
        if three[i % 10] == ans:
            cnt_three += 1

    rank['수포자1'] = cnt_one
    rank['수포자2'] = cnt_two
    rank['수포자3'] = cnt_three

    all_rank_values = rank.values()
    max_rank_values = max(all_rank_values)

    for i in range(len(rank)):
        if rank[f'수포자{i + 1}'] == max_rank_values:
            answer.append(i + 1)

    return (f'\n총 문제 {len(answers)}개 중\n\n1번 학생이 {cnt_one}개 \n2번 학생이 {cnt_two}개\n3번 학생이 {cnt_three}개로\n\n{answer}번 학생이 1등입니다.\n')

while True:
    try: 
        question_num = int(input("몇 문제를 출제하시겠습니까?(최대 10,000): "))
        if question_num > 10000:
            print("숫자가 너무 큽니다 10,000까지의 숫자를 입력해주세요")
        elif question_num < 1:
            print("최소 1이상의 숫자를 입력해주세요")
        else:
            for value in range(0, question_num):
                question_answers.append(random.randint(0, 5))
            print(solution(question_answers))
            break

    except ValueError:
        print("입력값은 정수만 허용됩니다.")

while문 위쪽도 정석 풀이에서 조금 수정하긴 했지만, while문 밑이 코드를 개조하며 추가 된 부분이라고 생각하는게 좋을 것 같다.

solution함수의 원래 기능은 몇 번이 가장 많이 맞췄는지만 리턴해줬지만, 코드를 작성한 것에 비해 결과물이 초라한 것 같아 리턴 값에 f-string을 이용해 몇 문제 중 학생들이 얼마나 맞췄는지도 나올 수 있게 수정했다. 이 과정 중 리턴 값이 한 줄에 다 나오는 게 보기 좋지 않아서 구글링을 해본 결과 \n을 이용하면 출력물을 줄바꿈 할 수 있다는 것을 알게 되었다.

solution함수 안에 for문은 원래 예시는 이런 코드였다.

for i in range(1, len(rank)+1): // for문의 index 자체를 몇번째 수포자 인지 확인하는 용도로 사용 
        if rank[i] == max_rank_values:
            answer.append(i) // 위에서 구한 제일 많이 맞춘 경우의 값과 일치하면 해당 사람 번호를 answer에 추가

최대한 주어진 예시에 맞춰서 만들고 실행을 해보았을 때 마주쳤던 것은 Key Error라는 에러 메시지였는데 에러 메시지의 내용은 간단했다. if문 안에 들어가 있는 rank라는 변수는 딕셔너리 형태라서 키를 넣어줘야 값을 반환할 텐데 리스트처럼 인덱스 숫자만 넣고 있으니 발생한 에러였다.

이 문제를 해결하기 위해 해본 시도는 for문 안에rank라고 적혀있는 모든 단어들을 all_rank_values로 바꾸는 것이었다. 해당 변수는 이미 rank로 부터 값만 추출해온 상태이니 분명 될 것이라 생각했다. 그러나 또다시 에러 메세지가 출력됐고 이유를 찾기 위해 all_rank_values를 리턴해 봤는데 앞에 dict_values라는 문구 때문에 에러가 뜨는 것으로 확인됐다.

그래서 나온 해결책이 지금 코드로 쓰이고 있는 이 for문이다.

for i in range(len(rank)):
    if rank[f'수포자{i + 1}'] == max_rank_values:
        answer.append(i + 1)

예시에서 쓰였던 인덱스i 대신 f-string을 사용해 키를 입력할 수 있게 만들었다.

개조한 코드

while True:
    try: 
        question_num = int(input("몇 문제를 출제하시겠습니까?(최대 10,000): "))
        if question_num > 10000:
            print("숫자가 너무 큽니다 10,000까지의 숫자를 입력해주세요")
        elif question_num < 1:
            print("최소 1이상의 숫자를 입력해주세요")
        else:
            for value in range(0, question_num):
                question_answers.append(random.randint(0, 5))
            print(solution(question_answers))
            break

    except ValueError:
        print("입력값은 정수만 허용됩니다.")

이 코드는 풀이 힌트나 해설과 전혀 무관하게 본인 순수 재미에 의해 탄생한 코드라는 점을 미리 공지한다.

해당 코드는 사용자에게 직접 출제 문제 수를 입력받고자 만들게 되었다. random함수를 사용하기 위해 random을 import 해주고 시작했다.

단순히 그냥 input을 넣어 만들다 보니 사용자가 음수나 소수를 쓰거나 문자를 사용했을 때 오류가 나는것을 확인했다.

이를 방지하기 위해 try-except문을 사용해 whileTrue로 놓고 원하는 값이 들어오면 함수를 실행시킨 뒤 break를 넣어 반복문을 종료 시켰고, 정수인 숫자가 아니거나 문자가 입력되어 오류가 나서 ValueError가 나왔을 경우 except처리해서 다시 입력을 받을 수 있게 만들었다.

느낀 점

만들어진 코드만 놓고 보면 정말 쉬운 코드라고 개인적으로 생각한다. 심지어 쓰는 와중에도 잘못된 것들이 보이는 코드인 것이 맨 위에 만들어 놓은 question_answer라는 변수도 굳이 전역변수가 아닌 지역변수로 넣었어야 했다. 이 외에도 코드를 더 간결하게 만들거나 필요 없는 코드들도 조금씩은 보인다.

최대한 예시를 따라가며 완성하긴 했으나 아직 예시를 보고서도 제대로 따라가지 못했다는 점에서 분발해야 한다는 생각이 들었고, 스스로 개조시킨 코드는 남의 코드가 아닌 내가 만들고 싶은 것을 찾아가며 만들었는데 이 과정이 정말 재밌어서 시간 가는 줄도 모르고 몰입했었던 것 같다.

앞으로 코딩을 배워나가며, 내 스스로 만들고 싶은 코드를 생각해 내는 것이 내 코딩 학습에 중요한 부분이 될 것 같다.

profile
이제 막 개발 배우는 코린이

0개의 댓글