[인생 프로그래밍] 조건문 (Conditional Statements)

Rex·2022년 1월 16일
0

인생 프로그래밍

목록 보기
20/33

조건문 (Conditional Statements)

우리의 삶은 선택의 연속이다. 어제도 당신은 1,000가지가 넘는 선택을 했을 것이다. 우리는 그 모든 선택이 너무나 자연스럽고 순간적으로 이루어지기 때문에 '선택했다' 라는 것을 인식하지 못할 뿐이다. 만약 [배가 고프면] 식사를 할 것이고, 만약 [먹고 싶은 메뉴가 있다면] 해당 메뉴를 먹으려고 할 것이다. 타이핑 중에 만약 [오타가 발견되면] 지우고 다시 작성할 거고, 만약 [간절히 원하던 물건이 좋은 가격에 판매 중이라면] 구매할 것이다. 우리가 하는 모든 행동들은 의식적이든 무의식적이든 '특정 조건 속에서' 행동으로 이어진다.

지금 휴대폰의 [남은 배터리 잔량]을 확인해 보자. 몇 퍼센트 남았는가? 지금 충전을 할까, 말까? 만약 [현재 충전 중이라면], 계속 충전되도록 놔둘까, 그만할까? 우리는 매일매일 특정한 상황, 조건 속에서 셀 수 없이 많은 선택들을 한다.

  • 휴대폰의 [배터리 상태]에 따라 충전을 할지 말지
  • 일기예보의 [강수확률]에 따라 우산을 챙길지 말지
  • [교통상황]에 따라 버스 / 지하철 / 자동차 / 기차 / 비행기 중에 무엇을 탈 것인지

지금 당장, 또는 예상하는 미래가 어떠한 상황이냐, 어떠한 조건이냐에 따라 우리의 행동은 달라진다.

프로그래밍은 인생의 축소판이다. 인생의 모든 찰나의 순간마다 나도 모르게 선택을 하는 것처럼, 프로그래밍에서도 매 순간 조건에 따라 선택해야 하는 경우가 많을 수밖에 없다. 그렇기에 조건문은 프로그래밍에서 정말 떼려야 뗄 수가 없는 기본적이면서 핵심적인 문법인 것이다.


IF Statement (if / else if / else)

대다수의 프로그래밍 언어는 if / else if / else 의 세트로 조건을 나눌 수 있다. 이것을 if 문 (if statement) 이라고 한다. 몇몇 프로그래밍 언어는 else if 대신 elif 처럼 하나의 키워드로 줄여서 쓰는 경우도 있는데, 파이썬이 그렇다.

if (|거짓 값):
    print('위 조건이 참이면 실행할 코드')
    ...

elif (|거짓 값):
    print('첫 번째 if 문의 조건이 거짓이고, 위 조건이 참이면 실행할 코드')
    ...

elif (|거짓 값):
    print('두 번째 if 문의 조건이 거짓이고, 위 조건이 참이면 실행할 코드')
    ...

# elif 여러 개 추가 가능

else:
    print('모든 if 문들의 조건이 거짓이면 실행할 코드')
    ...

파이썬의 문법: 들여 쓰기(indent)

들여 쓰기는 글자 앞의 공간을 말한다. 위 코드의 if (참|거짓 값): 아래의 코드부터 앞 부분에 띄어쓰기를 한 게 보이는가? 이렇게 들여 쓰기를 하면 새로운 코드 블록으로 인식한다. 파이썬은 특정 코드 블록을 형성할 때, 문법적으로 반드시 앞에 공백이 있어야 올바르게 인식하도록 설계 되어있다. 모든 언어가 이런 특징을 가진 것은 아니다. JavaScript 는 중괄호 { } 를 통해 코드 블록을 형성한다. 코드 들여 쓰기는 대부분 4개의 space 를 사용하는 것이 일반적이다.

if 문으로 날씨에 따라 우산을 가져갈지 말지 결정하는 과정을 의사 코드(pseudocode)로 작성해 보면 아래와 같다.

현재날씨 = 날씨확인()  # 현재 날씨를 받아오는 함수 실행

if (현재날씨 == 지금_비가_오는중):
    우산챙기기()
    
elif (강수확률 >= 70):  # 지금은 비가 안 오지만, 일기예보 강수확률은 70% 이상인 상태
    우산챙기기()

else:  # 비도 안 오고, 강수확률도 70% 이상이 아닌 경우
    빈손으로나가기()

지난번에 이야기했듯 의사 코드는 실제로 실행 가능한 코드가 아니라 우리 머릿속에 있는 논리를 문장으로 풀어놓은 것이기 때문에, 위의 코드는 당연히 실행할 수 없다. 지금은 if 문의 예시를 보는 것뿐이니 이해에 도움이 되었길 바란다.

또 다른 예시를 들어서, 아침 7시에는 반드시 일어나야 한다고 생각해 보자. 모닝콜을 오전 6시 50분에 맞췄는데 도저히 일어나기가 싫은 날이다. 그래서 '5분 뒤 다시 알림' 버튼을 클릭했고 눈을 감았다. 6시 55분에 알람이 울렸지만 여전히 너무 힘들어서 또 5분 뒤 다시 알림을 눌렀다... 결국 7시에 알람이 울렸고, 이제는 정말 피곤해도 반드시 일어나야 한다.

위 과정을 의사 코드로 작성해 보면 대략 아래와 같이 작성해 볼 수 있을 것이다.

if (모닝콜_울리는중 and 현재시각 == 7):
    침대에서_일어나기()
    
elif (모닝콜_울리는중 and 현재시각 == 655):
    5분_뒤_다시알림()
    
elif (모닝콜_울리는중 and 현재시각 == 650):
    5분_뒤_다시알림()

else:
    잠자기()

조건문 심화 응용

인생에 매일매일 수많은 선택이 존재하듯 프로그래밍 또한 매 순간 선택할 것들이 너무 다양하기 때문에 조건문을 여러 가지 방법으로 응용할 수 있다. 실제로 프로그래머들이 많이 사용하는 기법을 소개하겠다.

암묵적 Boolean (Implicit Boolean comparisons)

대부분의 프로그래밍 언어에는 특정 값을 암묵적으로 Boolean 의 False 로 취급하는 경향을 가지기도 한다. 인터넷을 찾아보면 '암묵적', '암시적', '묵시적' 등으로 단어를 다르게 사용하기도 하는데, 모두 같은 의미이다.

그러면 파이썬에서 어떤 값들이 암묵적으로 False 로 취급되는지 실험해 보자.

print(bool(0))   # False
print(bool(1))   # True
print(bool(-1))  # True
print()  # 콘솔의 실행 결과를 쉽게 구분하기 위해 빈 줄(empty line) 을 추가

print(bool(0.00))   # False, 0은 False 로 취급
print(bool(0.01))   # True, 0이 아닌 모든 수는 True 로 취급
print(bool(-0.01))  # True, 0이 아닌 모든 수는 True 로 취급
print()

print(bool(''))     # False, 빈 문자열
print(bool('안녕'))  # True
print()

print(bool(True))   # True
print(bool(False))  # False
print()

print(bool([]))        # False, 빈 배열(Empty Array) (참고로, 빈 튜플(Empty Tuple)도 False 로 취급)
print(bool([0]))       # True, 값이 존재하는 배열
print(bool(()))        # False, 빈 괄호는 공백과 같음
print(bool((0)))       # False, 단순한 0과 같음
print(bool((1)))       # True, 단순한 1과 같음
print(bool((0,)))      # True, 값이 존재하는 튜플(Tuple)
print(bool({}))        # False, 빈 Dictionary 객체
print(bool({'a': 0}))  # True, 값이 존재하는 Dictionary 객체
print(bool(None))      # False, 아무 의미 없는 값
print(bool())          # False, 아무것도 존재하지 않는 상태

위에서 False 로 취급되는 코드는 펜으로 특별하게 표시해 보자. 이러한 값들을 "Falsy 값" 이라고 말한다. 반대는 "Truthy 값" 이다. 실제로 자주 사용되는 기법들이기 때문에 이 내용을 인지하고 있어야 다른 사람의 코드를 볼 때 혼란스럽지 않을 것이다. 그리고 내 코드를 더 간결하게 작성할 수 있게 될 것이다.

Python 의 Falsy 값들
0, 0.0, ""(empty string), False, [](empty array), {}(empty dict), None

단락 평가(Short-circuit Evaluation)

단락 평가(Short-circuit evaluation) 는 프로그래밍에서 조건문을 평가할 때 간편하게 사용되는 기법이다.
보통의 if 조건문을 생각해 보면, 참이면 if 블록 안의 코드가 실행되고, 거짓이면 else 블록 안의 코드가 실행된다. 단락 평가는 이 조건식을 평가할 때 조건식의 '왼쪽 부분' 만으로도 전체 조건식의 결과를 판단할 수 있다면, '오른쪽 부분' 은 평가하지 않는 기법이다. 이를 통해 빠르고 효율적인 검사가 가능해진다. 이는 바로 위의 '암묵적 Boolean' 을 응용해서 단락 평가 기법을 활용할 수 있다. 아래 코드를 보자.

print(0 and 1)  # 0
# 0 은 암묵적으로 False 로 취급(Falsy) 하고 and 연산이니 이후의 조건을 볼 필요가 없으므로 0 출력

print(1 and 2)  # 2
# 0 외의 숫자들은 암묵적으로 True 로 취급(Truthy) 하고 and 연산이니 이후의 조건을 봐야 하므로 두 번째 코드가 실행되어 두번째 값인 2 출력

print(0 or 1)  # 1
# 0 은 암묵적으로 False 로 취급(Falsy) 하고 or 연산이니 이후의 조건을 봐야 하므로 두 번째 코드가 실행되어 두 번째 값인 1 출력

print(-1 or 2)  # -1
# 0 외의 숫자들은 암묵적으로 True 로 취급(Truthy) 하고 or 연산이니 이후의 조건을 볼 필요가 없으므로 -1 출력

위의 원리를 조금 더 응용해 보자.

변수1 = 0 and '이것은 string 데이터'
print(변수1)  # 0
# 첫 번째 조건이 거짓으로 판단(Falsy) 되고, and 연산이니 이후의 조건을 볼 필요가 없으므로 첫 번째 코드만 실행되어, 변수는 첫 번째 값으로 초기화 됨

변수2 = None or '이것은 string 데이터'
print(변수2)  # '이것은 string 데이터'
# 첫 번째 조건이 거짓으로 판단(Falsy) 되지만, or 연산이니 이후의 조건을 봐야 하므로 두 번째 코드까지 실행되어, 변수는 두 번째 값으로 초기화 됨

변수3 = 123 and ''
print(변수3)  # '' (빈 문자열이므로, 콘솔에서는 빈 줄로 표시됨)
# 첫 번째 조건이 참으로 판단(Truthy) 되고, and 연산이니 이후의 조건을 봐야 하므로 두 번째 코드까지 실행되어, 변수는 두 번째 값으로 초기화 됨

변수4 = 123 or ''
print(변수4)  # 123
# 첫 번째 조건이 참으로 판단(Truthy) 되지만, or 연산이니 이후의 조건을 볼 필요가 없으므로 첫 번째 코드만 실행되어, 변수는 첫 번째 값으로 초기화 됨

단락 평가가 이해되는가? 위의 코드들이 완벽하게 이해되지 않아도 괜찮다. 단락 평가는 프로그래밍의 심화 응용 단계에서 활용하는 수준으로서, 입문 단계에서는 개념만 이해해도 좋다.

단락 평가는 조건식을 평가할 때 꼭 필요한 부분만 평가해서 연산 속도를 높이고, 불필요한 연산을 줄이는 효과가 있다. 그리고 코드가 더 짧아지기도 하며, 코드의 가독성을 높여주기도 한다.

Q. 단락 평가 기법에서 왜 결과가 True / False 가 아닌, 값 자체가 나오는가?
A. 논리 연산자(and 또는 or)는 양쪽의 값으로 참/거짓을 판별하는 연산자일 뿐, boolean 을 만들어내진 않는다. 비교 연산자(==, !=, <=, >= 등)는 boolean 을 만들어내지만 논리 연산자는 참/거짓만을 판단한다. boolean 값을 인위적으로 만들어내기 위해서는 위의 암시적 boolean 에 나온 것처럼 bool() 함수를 사용할 수 있다. 논리 연산자는 암시적으로 참/거짓을 판별하는 것뿐이므로, 단락 평가와 같은 응용을 할 수 있도록 만들어져 있다.

if 문의 모든 것을 알아보았다. 프로그래밍에는 또 다른 방식으로 조건을 평가할 수 있는 방법이 있는데, 그것은 switch 문(switch statement) 이다. if 문과 비슷하지만 쓰임새나 특징이 조금 다르죠. 현재 파이썬 과정을 진행 중 이라면 아래의 자바스크립트 설명은 건너뛰고 switch 문의 설명으로 이동하자.


JavaScript 의 if statement

if (모닝콜_울리는중 and 현재시각 === 7) {
    침대에서_일어나기();
} else if (모닝콜_울리는중 and 현재시각 === 655) {
    5분_뒤_다시알림();
} else if (모닝콜_울리는중 and 현재시각 === 650) {
    5분_뒤_다시알림();
} else {
    잠자기();
}

Switch Statement (switch / case / break / default)

대부분의 프로그래밍 언어는 if 문과 함께 switch 문(switch statement)이라는 방식으로 조건을 설정할 수도 있다. if 문에서 if / else if / else 의 세트로 나누었던 것처럼, switch / case / break / default 의 세트로 조건을 설정할 수 있다.

if 문과 switch 문의 차이는 '조건이 범위인가 고정값인가' 에 따라서 사용을 달리할 수 있다. if 문은 조건이 범위든 고정 값이든 모두 사용할 수 있고, switch 문은 조건이 고정 값일 때에만 사용할 수 있다. 프로그래밍 식으로 비교하면, if 문은 boolean 값으로 조건을 나누고, switch 문은 고정적인 constants(상수값) 으로 조건을 나눈다고 할 수 있다.

결국 그 어떤 비교라도 boolean 형태로 만들 수 있으니, switch 문 없이 오로지 if 문 만을 사용해도 프로그래밍 상의 모든 문제를 해결할 수 있다. 그럼에도 switch 문을 사용하는 이유는 대표적으로 3가지가 있다.

  1. if 문은 코드를 순차적으로 해석하면서 여러 개의 조건을 비교하여 선택하는데 반해, switch 문은 고정 값(상숫값)을 사용하기 때문에, 조건의 비교 과정 없이 스위치 똑딱이를 누르듯 즉시 선택하므로 if 문보다 성능이 빠른 편이다. (이를 'Jump table' 이라고 함)
  2. 코드의 가독성이 조금 더 좋아지는 편이라, 가독성을 위해서 사용하기도 한다. (호불호 갈릴 수 있음)
  3. 상황에 따라 break 키워드의 사용 여부를 결정할 수 있어서, 여러 개의 케이스를 쉽게 관리할 수도 있다.

Python 의 Match statement

파이썬에서는 'switch' statement 가 아니라, 'match' statement 라고 부르는데, 보통의 switch 문과 거의 비슷한 동작을 수행한다. match / case 라는 키워드로 구현되어 있다. break 키워드가 없는 등 미묘한 차이는 있지만 본질적으로는 비슷한 문법이다.

count = "둘"

match count:
    case "하나":
        print("케이스: '하나' 입니다.")

    case "둘":  # 이 영역이 실행됨
        print("케이스: '둘' 입니다.")

    case "셋":
        print("케이스: '셋' 입니다.")

    case _:  # default 키워드와 비슷한 역할
        print("match 되는 case 가 없습니다.")

위의 코드는 count 변수에 "둘" 이라는 값을 할당하고, match 문에서 count 변수를 확인한 다음, count 변수와 정확히 매치되는 case 의 로직을 실행하는 코드이다. 그래서 결과는 "케이스: '둘'" 이 출력된다.

파이썬의 match 문은 기존의 switch 문에서 확장된 기능을 가지고 있지만, 지금은 그냥 일반적인 switch 문과 비슷하게만 사용해 보았다. 위의 구조가 일반적인 switch 문의 구조는 아니며, 정말 일반적인 switch 문의 구조는 JavaScript 코드에서 보게 될 것이다. 그래도 지금은 파이썬 과정을 진행 중이니 다른 언어의 코드를 보는 대신 정리하기로 바로 이동하길 권한다.


JavaScript 의 Switch statement

자바스크립트의 switch 문은 거의 모든 프로그래밍 언어에서 공통적으로 사용되는 매우 일반적인 switch 문의 형태이기 때문에 잘 기억해 두는 게 좋다. 위 Python 의 Match 문의 내용을 그대로 JavaScript 의 Switch 문으로 바꿔보겠다.

let count = "둘";

switch (count) {
    case "하나":
        console.log("케이스: '하나' 입니다.");
        break;
    
    case "둘":  // 이 영역이 실행됨
        console.log("케이스: '둘' 입니다.");
        break;
    
    case "셋":
        console.log("케이스: '셋' 입니다.");
        break;
    
    default:
        console.log("기본적으로 실행됩니다.");
}

바로 위에서 Python 의 match 문이 일반적인 switch 문의 구조가 아니라고 했던 것은 break 키워드를 사용하지 않았기 때문이다. 그리고 파이썬의 match 문에서는 default 키워드 대신 case _: 를 사용했다는 차이가 있다.

switch 문을 사용할 때, 한 가지 주의해야 할 점은 break 키워드의 활용과 관련된 것인데, break 키워드는 코드의 실행을 중단하고 해당 영역을 탈출하겠다는 의미이다. 파이썬의 반복문에서 break 키워드로 반복 영역을 탈출한 것과 동일한 역할을 한다. 자바스크립트에서 '영역'은, 중괄호 { } 가 기준이 된다고 생각하면 된다. 그러니까 break 키워드를 만나면, 중괄호로 영역이 묶여있는 switch 문이 즉시 종료된다. 그런데 만약 break 를 만나지 않으면 어떻게 될까?

위 코드에서 case "둘" 영역 안에 있는 break 문을 제거하는 경우 case "셋" 까지 같이 실행되고, 만약 정해놓은 case 에서 찾지 못하면 default 영역만 실행된다. 위 코드에서 count 값을 "넷" 으로 할당한다면 "기본적으로 실행됩니다." 가 출력 된다.

let count = "둘"

switch (count) {
    case "하나":
        console.log("케이스: '하나' 입니다.");
        break;
    
    case "둘":  // 이 영역이 실행됨
        console.log("케이스: '둘' 입니다.");
    
    case "셋":  // break 키워드가 없으므로 이 영역도 실행됨
        console.log("케이스: '셋' 입니다.");
        break;
    
    default:
        console.log("기본적으로 실행됩니다.");
}

위의 코드처럼 case "둘" 에서 break 키워드를 사용하지 않는다면 해당 case 부터 아래로 break 키워드를 만날 때까지 순차적으로 모든 case 를 실행하게 되어있다. break 가 전혀 없으면 default 까지 다 실행하게 된다. 위의 코드에서 count 변수를 "둘" 로 설정했는데, case "둘"break 키워드가 없으니 실행 결과는 아래와 같이 출력된다.

케이스: '둘' 입니다.
케이스: '셋' 입니다.

만약 case "셋" 에서도 break 키워드를 사용하지 않는다면, case "둘", case "셋", default 의 영역이 모두 실행되면서 아래와 같은 결과가 나오게 된다.

케이스: '둘' 입니다.
케이스: '셋' 입니다.
기본적으로 실행됩니다.

break 키워드의 역할이 정확하게 이해되었는가? 이렇게 break 키워드를 적재적소에 활용하면, if 문에 비해서 '범위' 를 선택하기 어렵다는 switch 문의 약점을 보완해 줄 수도 있다. 이 break 키워드는 switch 문 외에도 for 문, while 문 등의 반복문에서도 자주 사용되는 키워드이기 때문에 잘 알아두길 바란다.


정리하기

  1. 조건 문의 종류
    • if 문, switch 문
  2. break 키워드
    • switch 문, 반복문 등을 탈출하는 데 사용하는 키워드

생각 해보기

우리의 삶에서 선택의 순간을 생각해 보자. 그리고 그 선택에 작용하는 조건이 무엇이었는지도 생각해 보자.

"인생이 선택의 연속이듯, 프로그래밍 또한 선택의 연속이다."


연습 문제

다음 과정을 시작하기 전에 풀어보길 권장하는 문제이다. 이 문제를 해결하지 못하더라도 다음 과정으로 넘어갈 수 있지만, 풀어낸다면 정말 큰 학습이 될 것이다. 어렵지 않으니까 천천히 읽고 구현해 보자.

  1. 현재 휴대폰 배터리 잔량을 확인하고 battery 라는 변수에 숫자로 초기화하라.
  2. status 라는 변수를 만들고 '충전중' 또는 '충전중아님' 을 현재 휴대폰 상태에 맞게 입력하라.
  3. 당신이 일상생활에서 보편적으로 충전을 시작하는 지점을 point 라는 변수에 숫자로 초기화하라. 예를 들어 보편적으로 15% 남았을 때 충전을 한다면 15 라는 값을 넣으면 된다.
  4. 만약 battery 의 값이 point 보다 작거나 같으면서, status'충전중아님' 이라면, '충전을 시작합니다.' 라는 문장을 print() 함수로 출력하고, status'충전중' 으로 바꾸어라.
  5. 만약 battery 의 값이 point 보다 작거나 같으면서, status'충전중' 이라면, '현재 충전중 입니다.' 라는 문장을 print() 함수로 출력하라.
  6. 만약 battery 의 값이 point 보다 크면서, status'충전중아님' 이라면, '배터리가 여유롭습니다.' 라는 문장을 print() 함수로 출력하라.
  7. 만약 battery 의 값이 point 보다 크면서, status'충전중' 이라면, '충전기를 해제해도 좋습니다.' 라는 문장을 print() 함수로 출력하라.
  8. 만약 battery 의 값이 100 이면서, status'충전중' 이라면, '충전기를 해제합니다.' 라는 문장을 print() 함수로 출력하고, status'충전중아님' 으로 바꿔어라.
  9. 모든 실행 결과를 코드 옆에 주석으로 달아보자.
  • 지금 Python 과정을 하고 있다면, Python 으로 풀어야 한다.
  • Python 과정을 모두 마치고 JavaScript 를 시작했다면, JavaScript 로 풀어야 한다.
  • JavaScript 과정을 모두 마치고 Java 를 시작했다면, Java 로 풀어야 한다.
  • 너무 어려우면 ChatGPT 에게 도움을 요청하자.

궁금증 / 질문 / 개선점이 있다면 꼭 댓글을 달아주세요. 제가 최선을 다해 도와드리겠습니다. 여러분들의 최고의 학습 친구가 되어드리겠습니다.

#인생프로그래밍 #개발자렉스 #프로그래밍 #프로그래머 #개발자 #개발입문 #프로그래밍입문서적 #코딩교육 #코딩무료교육 #파이썬 #자바스크립트 #자바 #파이썬기초 #파이썬독학 #파이썬책 #혼자공부하는파이썬 #혼공파 #자바스크립트책 #앱개발 #어플개발 #ProgrammingOfLife #programming #programmer #coding #software #developer #python #javascript #java

profile
🔥 from Abstraction to Realization

0개의 댓글