Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 

README.md

test/ — 습작 모음 (부록)

step 체계에 편입되지 않은 실습 파일들입니다. 원본 수업 기록이라 고치지 않고 그대로 두었습니다.

클래스와 람다는 이제 정식 챕터에서 배웁니다 — step07_class 와 step06_function. 아래 class_ex_01.py 의 버그를 고친 정본은 step07_class/calculator.py 에 있습니다.

파일 지도

파일 성격
class_ex_01.py ★ 클래스 + 예외 처리 + 람다 — 이 저장소에서 가장 복잡한 코드. ⚠️ 결함 있음
lambda1.py 람다(익명 함수) 최소 예제
randomEx.py step03_controlstmt/randomEx.py 의 초기판. 정본은 step03 쪽
argeEx.py step03_controlstmt/inputex/argvEx.py 의 초기판. 정본은 step03 쪽 (파일명 arge 는 argv 오타)
testfile.py 저장소 최초 업로드 테스트용 5줄

중복 파일 2개는 지우지 않고 남겼습니다. step03 정본과 나란히 놓고 보면 수업이 진행되면서 코드가 어떻게 다듬어졌는지 보입니다. 예를 들어 randomEx.py 는 초기판에 없던 주석과 choice/sample 설명이 정본에 붙어 있습니다.

내용이 아예 없던 switchEx.py(0바이트)만 제거했습니다. 정본은 step03_controlstmt/switchex/switchEx.py 입니다.

실행 방법

python3 test/lambda1.py         # 입력 불필요
python3 test/randomEx.py        # 입력 불필요
python3 test/testfile.py        # 입력 불필요

python3 test/class_ex_01.py     # ← 무한 루프. 종료는 Ctrl+C
python3 test/argeEx.py 1 2 3    # ← 인자 3개 필수

짚고 갈 지점

클래스의 기본 구조

class Calculator:
    def __init__(self):          # 생성자 — 객체가 만들어질 때 자동 호출
        self.result = 0
        self.x = 0
        self.y = 0

    def setData(self, num1, num2):   # 메서드는 첫 인자로 self 를 받는다
        self.x = num1
        self.y = num2

    def add(self):
        self.result = self.x + self.y
        return self.result

cal1 = Calculator()              # 객체 생성 → __init__ 이 실행된다
cal1.setData(3, 4)               # self 는 자동으로 넘어간다 (인자 2개만 쓴다)
print(cal1.add())                # 7
  • self 는 그 객체 자신을 가리킵니다. 메서드 정의에는 반드시 쓰지만, 호출할 때는 넘기지 않습니다.
  • self.x 처럼 self. 를 붙인 값은 객체가 계속 들고 있습니다. 그냥 x = num1 이라고 쓰면 메서드가 끝나는 순간 사라집니다.

람다 — 이름 없는 한 줄 함수

add = lambda a, b: a + b     # def add(a, b): return a+b 와 같다
print(add(3, 4))             # 7

lambda1.py 가 최소 예제입니다. 짧은 함수를 변수에 담아 쓸 수 있습니다.

알려진 결함 — class_ex_01.py

이 파일에는 찾기 어려운 진짜 버그가 있습니다. 실행해서 재현해 보세요.

연산 종류 (+,-,*,/) : +
첫 번째 입력값 : 10
두 번째 입력값 : 0
숫자를 입력하세요.        ← ??? 숫자를 넣었는데?

덧셈을 요청했고 숫자만 입력했는데 "숫자를 입력하세요"가 나옵니다. 원인은 이 한 줄입니다.

test = lambda x: {"+": cal1.add(), "-": cal1.sub(), "*": cal1.mul(), "/": cal1.div()}.get(x, "연산 종류가 틀리다")
무슨 일이 벌어지나

dict 를 만드는 순간 값 자리의 함수가 전부 호출됩니다.

{"+": cal1.add(), ...} 에서 cal1.add() 는 "덧셈 함수"가 아니라 "덧셈을 실행한 결과값" 입니다. 괄호 () 가 붙어 있으니까요. 그래서 dict 가 만들어질 때 add·sub·mul·div 가 네 개 다 실행됩니다.

.get(x) 는 이미 계산이 끝난 네 값 중 하나를 고를 뿐입니다. 고르기 전에 이미 다 돌아간 뒤입니다.

두 번째 값이 0 이면 div() 가 ZeroDivisionError 를 냅니다. 덧셈을 요청했어도 마찬가지입니다. 그리고 그 예외를 아래의

except Exception as e:
    print("숫자를 입력하세요.")

가 종류를 가리지 않고 전부 잡아서 엉뚱한 메시지를 냅니다. 진짜 원인(ZeroDivisionError)은 e 에 담겨 있는데 출력하지도 않습니다.

고치는 방향은 두 가지입니다.

  1. 괄호를 떼서 함수 자체를 담고, 고른 다음에 호출합니다.
    ops = {"+": cal1.add, "-": cal1.sub, "*": cal1.mul, "/": cal1.div}   # () 없음
    func = ops.get(three)
    print("결과 : ", func() if func else "연산 종류가 틀리다")
  2. 예외를 종류별로 나눠 잡습니다.
    except ValueError:
        print("숫자를 입력하세요.")
    except ZeroDivisionError:
        print("0으로 나눌 수 없습니다.")

except Exception 으로 전부 삼키면 버그가 사용자에게 거짓말로 도착합니다. 이 파일이 그 실물 사례입니다.

두 가지를 모두 적용한 완성본이 step07_class/calculator.py 입니다. 먼저 직접 고쳐 본 뒤에 비교해 보세요.

이 함정은 step03_controlstmt/switchex/switchEx.py 의 dict switch 패턴을 응용하다 생겼습니다. 원본은 값이 1, 2, 3 같은 상수라 문제가 없었지만, 값 자리에 함수 호출을 넣는 순간 성질이 달라집니다.

그 밖에 이 파일에는:

  • while True: 에 종료 조건이 없어 Ctrl+C 로만 빠져나올 수 있습니다.
  • except 가 잡은 e 를 쓰지 않습니다. print(e) 한 줄만 있어도 원인이 바로 보였을 겁니다.

지금은 이렇게 바뀌었습니다

  • 단순히 값을 담는 클래스라면 @dataclass 로 짧게 쓸 수 있습니다.

    from dataclasses import dataclass
    
    @dataclass
    class Calculator:
        x: int = 0
        y: int = 0
        result: int = 0
  • 연산자 대응은 operator 모듈을 쓰면 직접 만들 필요가 없습니다.

    import operator
    ops = {"+": operator.add, "-": operator.sub, "*": operator.mul, "/": operator.truediv}
    print(ops[three](one, two))

    값 자리에 함수 자체(괄호 없음)가 들어간다는 점을 위 버그와 비교해 보세요.

  • except Exception 은 지금도 그때도 나쁜 습관입니다. 잡을 예외를 구체적으로 적고, 잡았다면 최소한 로그를 남깁니다.

연습 과제

  1. class_ex_01.py 를 실행해 + / 10 / 0 을 입력하고 잘못된 메시지를 직접 재현하세요.
  2. except Exception as e: 아래에 print(e) 를 추가해 진짜 원인을 확인하세요.
  3. 위 알려진 결함의 1번 방향대로 dict 에서 괄호를 떼어 고치세요.
  4. 예외를 ValueError 와 ZeroDivisionError 로 나눠 각각 다른 메시지를 내도록 고치세요.
  5. q 를 입력하면 종료되도록 while True 에 탈출 조건을 넣으세요.
  6. Calculator 에 나머지(%)와 거듭제곱(**) 연산을 추가하세요.
  7. test/randomEx.py 와 step03_controlstmt/randomEx.py 를 나란히 열어 무엇이 추가됐는지 찾아보세요.