입력과 출력부터 실행하기
65분 안팎
학습 목표
정수 센서 입력을 읽어 범위를 벗어난 값에는 INVALID를 출력합니다.
개념
장치 없이 먼저 정하는 관찰 계약
센서 기록기를 만들 때 처음 확인할 것은 센서의 멋진 출력 화면이 아니라 입력을 어떤 값으로 받아 무엇을 내보낼지입니다. 장치가 아직 책상에 없어도 숫자를 주고 판단 결과를 비교할 수 있습니다. 여기서는 12비트 센서의 원시값을 흉내 내어 0부터 4095까지를 정상으로 정합니다. 이 범위는 이 프로젝트의 가정이며 모든 센서의 공통 규격은 아닙니다. 실제 센서를 붙일 때는 데이터시트의 분해능과 전송 형식을 다시 확인합니다.
이번 모듈의 처음 두 레슨은 브라우저 Python으로 판단 규칙을 익힙니다. 뒤의 두 레슨은 같은 규칙을 PC의 C 프로그램으로 옮깁니다. Python 코드를 보드에 설치하는 과정이 아닙니다. 본문 예제는 브라우저 실행기에 그대로 붙이고 입력 칸에는 지정한 데이터를 넣습니다. 로컬에서도 실행하려면 코드를 sensor_probe.py에 저장해 python3 sensor_probe.py로 실행합니다. 프롬프트 표시나 출력 내용은 코드 파일에 넣지 않습니다.
로컬 C 실습에는 gcc 명령으로 부르는 컴파일러와 make, Python 3가 필요합니다. macOS의 gcc는 Apple Clang일 수 있으므로 gcc --version의 첫 줄을 기록합니다. 저장소나 시스템 폴더에 파일을 흩뜨리지 않고 다운로드한 starter를 별도 폴더에 풉니다. 터미널의 pwd로 현재 폴더, ls로 Makefile과 소스를 확인한 뒤 명령을 실행합니다. 실습에는 외부 Python 패키지나 실물 보드가 필요하지 않습니다.
문자에서 정수, 정수에서 판정으로
표준 입력은 프로그램이 외부 데이터를 받는 통로입니다. input()은 한 줄을 읽어 문자열을 반환합니다. 화면에 2048을 넣어도 아직 수치 자료형이 아니므로 int()로 십진 정수로 바꿉니다. 변수 raw는 이번에 받은 원시값에 붙인 이름입니다. 이름은 값을 기억하고 재사용하기 위한 것이며 물리 센서나 메모리 주소를 뜻하지 않습니다. 대입문의 오른쪽을 계산한 뒤 왼쪽 이름에 연결합니다.
센서의 정상 조건은 두 경계를 동시에 만족하는 것입니다. Python의 0 <= raw <= 4095는 하한 이상이고 상한 이하라는 뜻입니다. 참이면 OK와 값, 거짓이면 INVALID 한 줄을 냅니다. if 뒤에는 콜론을 쓰고 참일 때 실행할 문장을 네 칸 들여씁니다. else는 같은 if와 맞춰 놓습니다. 출력 문장을 둘 다 블록 밖에 놓으면 정상과 비정상 표시가 함께 나와 계약을 깨뜨립니다.
정상 출력은 OK 2048처럼 상태와 숫자 사이에 공백 하나가 있습니다. print("OK", raw)는 두 인자 사이에 기본 공백을 넣고 끝에 줄바꿈을 붙입니다. print("OK raw")는 변수 값을 보지 않고 글자 raw를 그대로 내므로 목적이 다릅니다. 입력을 요청하는 안내 문구를 input("값: ")로 넣으면 채점 출력에 안내까지 섞입니다. 실습에서는 input()만 사용해 결과 데이터만 표준 출력에 둡니다.
범위를 벗어난 정수와 정수로 해석할 수 없는 글자는 다른 문제입니다. -1은 int로 변환되지만 센서 계약에서 거부할 값입니다. abc는 수치로 바꾸는 단계 자체가 실패합니다. 이번 브라우저 과제의 입력은 십진 정수 한 개이며 abc를 처리하는 기능은 요구하지 않습니다. 나중의 C CLI에서는 형식 오류를 별도로 처리합니다. 범위 검사를 추가했다고 모든 종류의 입력을 안전하게 받는다고 설명하지 않습니다.
작은 실험으로 조건의 의미를 확인합니다
입력 2048 하나가 성공했다고 양쪽 끝까지 맞다는 뜻은 아닙니다. 경계의 바로 안과 밖을 비교해야 연산자가 의도대로 쓰였는지 드러납니다. -1, 0, 4095, 4096을 각각 실행하고 출력 상태를 적습니다. 0과 4095를 포함하므로 < 대신 <=가 필요합니다. 정상값을 한 번 더 넣어 숫자 자체가 출력되는지도 확인합니다. 상태 문자열만 검사하면 엉뚱한 원시값을 출력하는 오류가 숨을 수 있습니다.
따라하기에서는 먼저 int 변환만 하고 다음에 판정을 붙입니다. 이렇게 단계를 나누면 숫자가 잘못 읽혔는지 조건이 잘못됐는지 분리할 수 있습니다. 코드를 변경할 때마다 같은 입력을 다시 넣고 이전 출력과 비교합니다. 테스트에서 말하는 기대 출력은 우리가 계약으로 정한 결과입니다. 실행기가 낸 실제 출력과 기대 출력을 대조하는 일은 코드를 눈으로 읽는 것과 다른 증거를 줍니다.
센서 원시값 0은 값이 없다는 뜻으로 사용하지 않습니다. 이 프로젝트에서는 정상 범위의 최솟값입니다. if raw:로 참인지 판단하면 Python에서 0이 거짓이어서 정상값을 버립니다. 숫자가 존재하는지, 숫자가 0인지, 범위가 맞는지를 구별합니다. 실물에서는 단선 때문에 0이 읽힐 가능성도 있지만 그 진단에는 연결 상태나 추가 측정 정보가 필요하므로 지금의 범위 검사만으로 단선을 확정할 수 없습니다.
오류 문장을 읽고 한 부분씩 고칩니다
IndentationError가 보이면 먼저 if 다음 문장이 들여써졌는지 확인합니다. 콜론 누락은 SyntaxError로 나타날 수 있습니다. 에디터가 탭을 넣었는지 공백을 넣었는지도 봅니다. 여러 문장을 동시에 고치기보다 오류가 가리키는 줄과 그 직전 줄을 읽습니다. 구문을 복구한 뒤 경계 테스트를 다시 실행해야 조건의 실수까지 확인할 수 있습니다. 문법 오류가 사라진 것만으로 범위 계약은 증명되지 않습니다.
ValueError가 int() 줄을 가리키면 입력 칸의 글자를 봅니다. 2048.0은 정수 문자열이 아니고 OK 2048은 상태 문자열이 포함되어 있습니다. 이번 입력에는 숫자만 넣습니다. NameError가 raw를 가리키면 이름 철자와 대입 위치를 확인합니다. raw를 읽기 전에 사용하거나 다른 대소문자로 쓴 경우를 찾아 수정합니다. 오류를 INVALID로 숨기기 전에 형식 오류인지 프로그램 오타인지 구별합니다.
코드를 파일에 저장했는데 변화가 없다면 실행한 경로와 편집한 경로를 비교합니다. python3 sensor_probe.py에서 파일 이름은 실행 대상이고 python3 자체는 코드를 읽는 프로그램입니다. 결과를 복사할 때는 입력, 실제 출력, 사용한 코드 버전을 함께 적습니다. 브라우저 실습에서는 starter의 잘못된 고정 출력을 바꾸고 여섯 사례를 통과시키면 이 레슨의 목표를 직접 확인할 수 있습니다.
PC 입력은 현실의 잡음, 전압, 통신 지연을 나타내지 않습니다. 지금 얻은 근거는 정수 범위와 출력 형식이 일치한다는 것입니다. 신입 교육에서 이 구분을 먼저 익히면 장치가 응답하지 않을 때 수치 처리 오류와 연결 문제를 뒤섞지 않습니다. 실행 환경과 Python 기본 사용은 더 읽기의 시작 장에서 보충하고, 다음 레슨에서는 여러 값을 처리하면서 정상 샘플 수와 양 끝값을 계산합니다.
따라하기
입력값을 수로 읽기
입력 칸에 2048을 넣습니다. 변환한 수가 출력에 들어가는지 봅니다.
raw = int(input())
print("OK", raw)
실행 결과
OK 2048
정상 하한 판단
입력 0으로 하한을 포함하는 조건을 실행합니다.
raw = int(input())
if 0 <= raw <= 4095:
print("OK", raw)
else:
print("INVALID")
실행 결과
OK 0
범위 밖 판단
같은 코드에 4096을 넣습니다. 상한 바깥에서는 상태만 출력합니다.
raw = int(input())
if 0 <= raw <= 4095:
print("OK", raw)
else:
print("INVALID")
실행 결과
INVALID
확인 문제
실습
십진 정수 한 개를 읽습니다. 0~4095이면 OK 값, 나머지는 INVALID를 한 줄로 출력합니다. 안내 문구는 출력하지 않습니다. 입력은 정수 형식이며 범위 거부와 원시값 보존을 여섯 사례로 검사합니다.
모범 답안
raw = int(input())
if 0 <= raw <= 4095:
print("OK", raw)
else:
print("INVALID")
더 읽기
면접 질문
- 센서 입력의 경계값을 시험할 때 정상값 0을 어떻게 구분하나요?