3. 값과 연산#
프로그래밍언어의 핵심 기능 중의 하나가 바로 컴퓨터에 저장된 값을 조작하는 일이다. 이번 장에서는 가장 많이 사용되는 값의 종류를 소개하고, 연산자를 이용하여 주어진 값으로부터 새로운 값을 생성하는 연산을 다룬다.
먼저 주어진 값에 따라 다른 일을 하도록 명령하는 조건문의 기초 활용법을 알아본다.
3.1. 기초 명령문: 조건문#
컴퓨터 프로그램은 값을 저장하고 조작하여 새로운 값을 계산하여 활용하는 방법을 묘사한다. 이때 주어진 값에 따라 따라 다른 방법으로 일을 하도록 명령할 수 있다.
if … 조건문
예를 들어 아래 코드는 파이썬을 좋아하는 경우에만 ‘안녕!’과 ‘파이썬 좋아요.’ 두 문자열이 출력되도록 한다.
love_python = True
if love_python:
print("안녕!")
print("파이썬 좋아요.")
안녕!
파이썬 좋아요.
if love_python은 love_python이 참인지 여부를 확인하도록 하는 명령문이다.
그런데 1번 줄에서 love_python = True라고 작성되어 있기에
love_python이 참으로 확인되고,
따라서 들여쓰기된 print("안녕!")와 print('파이썬 좋아요.') 두 명령문이 차례대로 실행된다.
들여쓰기와 코드 블록
if love_python:에 콜론 기호 : 사용되고 이어지는 두 개의 명령문은 들여쓰기 이후에 작성되었음에 주의한다.
파이썬은 들여쓰기를 이용하여 명령문들로 구성된 코드 블록을 지정한다.
이렇게 동일한 정도의 들여쓰기 이후에 작성된 명령문으로 구성된 코드 블록은 특정 조건 하에서만 실행된다.
예를 들어 위 코드에서는 love_python이 참이기에 들여쓰기된 코드 블록이 실행되었다.
들여쓰기는 일반적으로 Tab 키를 이용하며, 일반적으로 Space 키를 4번 또는 2번 타입핑한 결과로 처리된다. 사용하는 편집기에 따라 들여쓰기 정도를 지정하는 옵션이 제공된다.
반면에 아래 코드를 실행하면 아무 것도 출력되지 않는다.
이유는 1번 줄에서 love_python이 거짓으로 확인되어 들여쓰기된 코드 블록이 실행되지 않기 때문이다.
love_python = False
if love_python:
print("안녕!")
print("파이썬 좋아요.")
if … else … 조건문
위 코드의 if lov_python 조건문에서 love_python이 거짓이어서 들여쓰기된 코드 블록이 실행되지 않았다.
그런데 그런 경우, 즉 if 다음이 거짓으로 판정될 때 실행되는 다른 코드 블록을 else 키워드를 이용하여 지정할 수 있다.
예를 들어 아래 코드는 파이썬을 좋아하지 않는 경우에 파이썬을 사랑해주면 행복진다는 문장을 출력한다.
love_python = False
if love_python:
print("안녕!")
print("파이썬 좋아요.")
else:
print("파이썬을 사랑해주세요!")
print("그러면 행복해집니다.")
파이썬을 사랑해주세요!
그러면 행복해집니다.
else 키워드 또한 콜론 기호 :로 끝나고 줄바꿈 후에 들여쓰기로 코드 블록을 지정함에 주의한다.
3.2. 값의 종류#
값values은 컴퓨터에 저장해서 활용할 수 있는 대상이다. 정수, 부동소수점, 문자열 이 대표적인 값들이며 이외에 부울값과 리스트 등 다양한 값들이 사용된다.
정수
정수는 …, -2, -1, 0, 1, 2, … 등 이미 알고 있는 것과 동일한 숫자를 가리킨다.
부동소수점
무리수를 포함한 모든 실수는 컴퓨터의 용량 한계로 인해 불완전하게 다뤄진다. 파이썬을 포함하여 모든 프로그래밍 언어는 유한소수와 무한소수 모두 소수점 이하 적당한 자리에서 끊어 저장한다. 소수점 이하 자릿수를 얼마로 할 것인가는 프로그램이 실행되는 환경에 따라 달라진다. 이런 의미에서 유한소수의 자료형을 부동소수점floating points이라 부른다.
문자열
정수, 부동소수점과 더불어
a, b, c, …, 가, 나, 다, …, !, :, ;, _, (, ), … 처럼
컴퓨터 키보드를 이용하여 입력할 수 있는 임의의 문자, 숫자, 기호로
구성된 문자열도 값이다.
예를 들어, 파이썬 좋아요;-), Hello, World! 등과 같은 문자열도 값이다.
이외에 파이썬은 리스트, 튜플, 집합, 사전 등 다양한 종류의 값을 제공하며,
앞으로 하나씩 상세히 살펴볼 것이다.
부울값
참과 거짓을 의미하는 True와 False를
부울값Boolean value
또는 진릿값이라 한다.
리스트
리스트list는 여러 개의 값을 항목으로 갖는 목록을 가리키는 값이다.
리스트는 대괄호 [] 로 항목들의 목록을 감싸고, 각각의 항목은 쉼표 , 로 구분한다.
예를 들어, 1부터 5까지의 정수로 구성된 리스트를 가리키는 변수를 다음과 같이 선언한다.
one2five = [1, 2, 3, 4, 5]
아래 name_list 변수는 사람들의 이름, 즉 문자열로 구성된 리스트를 가리킨다.
name_list = ['김강현', '황현', '남세원', '최흥선', '김현선', '함중아']
리스트의 항목은 서로 다른 종류의 값이 사용될 수도 있다. 예를 들어 아래 리스트는 김강현의 이름, 전화번호, 나이, 키, 출생지로 구성된 리스트를 정의한다.
kgh = ['김강현', '010-1234-5678', 20, 172.3, '제주']
기타 등등
정수, 부동소수점, 문자열, 부울값, 리스트 이외에 튜플, 사전, 파일 등 보다 복잡한 종류의 값도 사용한다. 앞으로 필요에 따라 하나씩 살펴볼 예정이다.
3.3. 연산자와 값#
일반적으로 사칙연산은 정수, 유리수, 실수 등을 대상으로 하는 수학 계산을 의미한다. 반면에 프로그래밍에서는 정수, 부동소수점 이외에 문자열, 리스트 등에 대해서도 연산이 지원된다.
연산자
연산자operator는 연산을 위해 사용되는 기호를 가리킨다. 프로그래밍에서 가장 많이 사용되는 연산자는 다음과 같다.
사칙 연산자:
+,-,*,/거듭제곱 연산자:
**비교 연산자:
<,>,<=,>=,==
언급된 연산자들이 정수와 부동소수점의 연산에 사용되면 수학에서의 연산과 동일하다. 그런데 다른 종류의 값에는 다르게 계산된다.
부울값 연산
등식, 부등식은 부울값으로 계산된다. 등식, 부등식처럼 부울값으로 계산되는 수식을 논리식이라 부른다. 아래 표는 기본 논리식과 의미를 담고 있다. 나중에 보다 복잡한 논리식을 정의하는 방법을 다룰 것이다.
기본 논리식 |
의미 |
|---|---|
a < b |
a가 가리키는 값이 b가 가리키는 값보다 작을 때 참 |
a <= b |
a가 가리키는 값이 b가 가리키는 값보다 작거나 같을 때 참 |
a > b |
a가 가리키는 값이 b가 가리키는 값보다 클 때 참 |
a >= b |
a가 가리키는 값이 b가 가리키는 값보다 크거나 같을 때 참 |
a == b |
a와 b가 동일한 값을 가리킬 때 참 |
a != b |
a와 b가 동일하지 않은 값을 가리킬 때 참 |
숫자와 함께 사용되는 기본 논리식의 의미는 일반적으로 알려진 것과 동일하다.
큰지 여부 판단
3 > 4
False
크거나 같은지 여부 판단
3 >= 4 - 1
True
작은지 여부 판단
5/3 + 1.2 < 3/2
False
작거나 같은지 여부 판단
2.3 <= 2.3 + 3.0
True
동치 여부 판단: 두 값이 동일할 때
True로 계산됨.
1 == 4/4.0
True
비동치 여부 판단: 두 값이 서로 다를 때
True로 계산됨.
1 != 2
True
= vs. ==
기호 = 는 변수 할당에 사용되는 기호이다.
기호 왼편에는 변수가, 오른편에는 특정 값을 표현하는 식이 사용된다.
예를 들어 z = 1+3은 변수 z가 1+3, 즉 4를 가리키도록 하는 명령문이다.
반면에 기호 ==는 두 개의 값이 동일한 값을 가리키는지 여부를 판단할 때 사용된다.
예를 들어 z == 2 * 3 - 2은 변수 z가 가리키는 값과 2+3-2가 동일한 값을 가리키는지 여부를 판단한다.
문자열 비교 연산
크기 비교는 다른 자료형에서도 가능하다. 두 문자열의 크기비교는 사전식 알파벳 순서를 사용한다. 대문자가 소문자보다 작음에 주의한다.
'A' <= 'a'
True
'apple' < 'Hello, World!'
False
'Hello, World!' < ' hello'
False
빈 문자열은 다른 문자열보다 항상 작다.
'' < 'a'
True
리스트 연산: 이어붙이기와 복제
+, * 등이 문자열, 리스트 등에 대해서도 특별한 방식으로 활용된다.
설명을 위해 아래 두 리스트를 이용한다.
first_languages = ['파이썬', 'C', '자바']
second_languages = ['C++', 'C#', '자바스크립트', 'Node.js']
리스트와
+연산자: 두 개의 리스트를 이어붙여 하나의 리스트로 계산
languages = first_languages + second_languages
languages
['파이썬', 'C', '자바', 'C++', 'C#', '자바스크립트', 'Node.js']
리스트와
*연산자: 주어진 리스트를 지정된 정수만큼 복제해서 이어붙인 리스트로 계산
languages * 2
['파이썬',
'C',
'자바',
'C++',
'C#',
'자바스크립트',
'Node.js',
'파이썬',
'C',
'자바',
'C++',
'C#',
'자바스크립트',
'Node.js']
문자열 연산: 이어붙이기와 복제
문자열에 대해서도 유사한 방식으로 +, * 연산자가 기능한다.
first = '파이썬, '
second = '안녕!'
문자열과
+연산자: 두 개의 문자열을 그대로 이어붙인 문자열로 계산
greetings = first + second
greetings
'파이썬, 안녕!'
문자열과
*연산자: 주어진 문자열을 지정된 정수만큼 복제해서 이어붙인 문자열로 계산
greetings * 3
'파이썬, 안녕!파이썬, 안녕!파이썬, 안녕!'
리스트 in 연산자
리스트에 항목으로 포함되어 있는지 여부는 in 연산자를 이용하며 결과는
부울값으로 계산된다.
예를 들어 파이썬은 first_languages가 가리키는 리스트에 포함되어 있고,
자바는 second_languages가 가리키는 리스트에 포함되어 있지 않다.
'파이썬' in first_languages
True
'자바' in second_languages
False
문자열 in 연산자
문자열에 대해서도 in 연산자를 사용할 수 있다.
아래 코드는 다양한 예제를 통해 greetings가 가리키는 문자열에 포함된
지정된 기호와 문장의 포함여부를 판정해 준다.
'!' in greetings
True
'?' in greetings
False
'파' in greetings
True
'파이썬' in greetings
True
', ' in greetings
True
'파이썬 안녕' in greetings
False
리스트 인덱싱
리스트에 포함된 각각의 항목은 고유의 인덱스index를 갖는다. 인덱스는 가장 왼쪽에 위치한 항목부터 차례대로 0, 1, 2, 3 … 로 지정된다. 그리고 인덱스를 이용하여 해당 인덱스의 항목을 확인하여 활용할 수 있는데 이를 인덱싱indexing이라 부른다.
설명을 위해 name_list가 가리키는 리스트를 활용한다.
print(name_list)
['김강현', '황현', '남세원', '최흥선', '김현선', '함중아']
가장 왼쪽에 위치한 항목, 즉 0번 인덱스의 항목을 확인하는 방법은 다음과 같다.
print(name_list[0])
김강현
왼쪽에서 세번째 항목은 인덱스가 2이기에 다음과 같이 확인한다.
print(name_list[2])
남세원
인덱스는 음의 정수로도 표현할 수 있다. 맨 오른쪽에 위치한 항목부터 왼쪽으로 이동하면서 차례대로 -1, -2, -3 등의 음의 인덱스를 갖는다. 따라서 가장 오른쪽에 위치한, 즉 리스트의 맨 끝에 위치한 항목은 다음과 같다.
print(name_list[-1])
함중아
변수 one2five처럼 숫자로 구성된 리스트를 많이 활용한다.
예를 들어 변수 scores는 세 개의 시험점수로 구성된 리스트를 할당받는다.
scores = [92, 87, 100]
변수 scores가 시험점수로 구성된 리스트를 가리키기에
아래 코드에서처럼 시험점수의 평균값을 인덱싱을 이용하여 계산할 수 있다.
참고로 정수의 나눗셈 결과는 항상 부동소수점으로 처리됨에 주의한다.
mean = (scores[0] + scores[1] + scores[2])/3
print(mean)
93.0
문자열 인덱싱
파이썬은 문자열을 여러 개의 문자 또는 기호로 구성된 값으로 간주한다. 따라서 리스트의 인덱스와 인덱싱 기능을 문자열에 대해서도 동일하게 적용할 수 있다. 즉, 문자열 가장 왼편에 위치한 문자 또는 기호부터 오른쪽으로 이동하면서 차례대로 0, 1, 2 등의 인덱스를 가지며 이를 이용하여 문자열 인덱싱을 사용할 수 있다.
예를 들어 name_list 리스트의 첫재 항목, 즉 0번 인덱스의 값인 김강현을
변수 kgh에 할당해보자.
kgh = name_list[0]
print(kgh)
김강현
김강현의 성인 김은 0번 인덱스의 항목이다.
kgh[0]
'김'
반면에 현은 김강현 문자열의 2번 인덱스의 항목이다.
kgh[2]
'현'
연산자 우선순위
여러 종류의 연산자를 이용할 경우 연산자들 사이의 우선순위를 고려해야 의도한 대로 계산된다. 정수와 부동소수점 관련 연산자들의 우선순위는 수학에서 배운 것과 동일하다.
괄호 안에 있는 표현식을 가장 먼저 계산한다.
2 * (3 - 1) => 2 * 2 => 4
(1 + 1) ** (5 - 2) => 2 ** (5 - 2) => 2 ** 3 => 8
거듭제곱이 사칙연산보다 우선순위가 높다.
3 ** 2 * 2 => (3 ** 2) * 2 => 9 * 2 => 18
3 * 2 ** 2 => 3 * (2 ** 2) => 3 * 4 => 12
곱셈과 나눗셈이 덧셈과 뺄셈보다 우선순위가 높다.
2 * 3 - 1 => (2 * 3) - 1 => 6 - 1 => 5
6 + 4 / 2 => 6 + (4 / 2) => 6 + 2.0 => 8.0
곱셈과 나눗셈은 서로 우선순위가 같다. 덧셈과 뺄쎔도 서로 우선순위가 같다. 같은 우선순위를 갖는 사칙 연산자가 연속해서 사용되면 왼쪽에 위치한 연산부터 먼저 실행된다.
60 / 2 * 3 => (60 / 2) * 3 => 30.0 * 3 => 90.0
만약에 오른쪽에 위치한 곱셈을 먼저 실행하면 다른 결과가 나온다.
60 / (2 * 3) => 60 / 6 => 10.0
거듭제곱이 연속해서 나오면 오른쪽 거듭제곱부터 실행된다.
2 ** 3 ** 2 => 2 ** (3 ** 2) => 2 ** 9 => 512
만약에 왼쪽부터 거듭제곱을 계산하면 다른 결과가 나온다.
(2 ** 3) ** 2 => 8 ** 2 => 64
연산의 결과
연산의 결과 또한 하나의 값이며, 따라서 저장하여 필요에 따라 활용된다. 예를 들어, 아래 코드는 1 더하기 2가 짝수인지 여부를 화면에 출력한다. 정수의 짝수 여부는 2로 나눈 값이 0인지 또는 1인지에 따라 결정되는 성질을 이용한다.
코드에 포함된 else: 명령문은 변수 whether_even가 거짓, 즉 False를 가리킬 때만
아랫쪽에 들여쓰기로 지정된 코드블록이 실행되도록 한다.
if whether_even:의 경우처럼
else:로 시작하는 코드 또한 콜론 :과 들여쓰기로 코드블록이 지정되었음에 주의한다.
onePtwo = 1 + 2
whether_even = onePtwo % 2 == 0
if whether_even:
print("짝수")
else:
print("홀수")
홀수
반면에 아래 코드는 2 더하기 2가 짝수인지 여부를 화면에 출력한다.
twoPtwo = 2 + 2
whether_even = twoPtwo % 2 == 0
if whether_even:
print("짝수")
else:
print("홀수")
짝수
3.4. 예제#
예제 1
먼저 아래와 같이 변수를 선언한다.
number = 17
언급된 값을 표현하는 수식을 number 변수를 이용하여 표현한 다음에 실행하여라.
(1) number 더하기 2
답:
number + 2
19
(2) number 빼기 2.0
답:
number - 2.0
15.0
(3) number 나누기 7
답:
number / 7
2.4285714285714284
(4) number를 7로 나눴을 때의 몫
답:
number // 7
2
(5) number를 7로 나눴을 때의 나머지
답:
number % 7
3
(6) number의 세제곱을 (2 + 3)으로 나누기
답:
number**3 / (2 + 3)
982.6
그런데 아래와 같이 하면 다른, 따라서 틀린 값이 나온다.
number**3 / 2 + 3
2459.5
이유는 나눗셈 연산자 /의 우선순위가 덧셈 연산자 + 보다 높아서 위 수식은 아래 수식처럼 계산되기 때문이다.
(number**3 / 2) + 3
2459.5
예제 2
아래 코드를 실행했을 때 부동소수점 27.1이 어떻게 이해되는지를 설명하라.
if 27.1:
print("참인 경우라서 실행됨!")
참인 경우라서 실행됨!
답:
파이썬에서 0은 False로, 다른 값은 True로 간주된다.
이런 의미로 if 27.1에 사용된 27.1은 부동소수점이면서 0이 아니기에
True로 간주되어 조건문의 본문에 포함된 print() 함수가 실행된다.
예제 3
아래 내용의 논리식을 할당받는 변수 p1을 선언한 후에 p1에 할당된 진리값을 확인한다.
3과 4가 다른지 여부 판단
답:
아래 코드는 두 값이 다른지 여부는 != 연산자를 이용하여 표현한다.
p1 = 3 != 4
print(p1)
True
예제 4
아래 내용의 논리식을 할당받는 변수 p2를 선언한 후에 p2에 할당된 진리값을 확인한다.
“hello”와 “hi”가 같은지 여부 판단
답:
아래 코드는 두 값이 동일한지 여부는 == 연산자를 이용하여 표현한다.
p2 = "hello" == "hi"
print(p2)
False
예제 5
15, 28이 각각 짝수인지 또는 홀수인지를 판별하는 코드를 작성한다. 출력된 결과는 아래와 같은 형식이어야 한다.
15는 짝수인가요? False
28은 짝수인가요? True
힌트: 짝수는 2로 나눴을 때 나머지가 0이다.
답:
15가 짝수인지 여부는 15 % 2 == 0 가 True로 계산되는지로 확인한다.
print("15는 짝수인가요?", 15 % 2 == 0)
print("28는 짝수인가요?", 28 % 2 == 0)
15는 짝수인가요? False
28는 짝수인가요? True
변수를 사용하면 좀 더 편리할 수도 있다.
even15 = 15 % 2 == 0
even28 = 28 % 2 == 0
print("15는 짝수인가요?", even15)
print("28는 짝수인가요?", even28)
15는 짝수인가요? False
28는 짝수인가요? True
예제 6
변수 second_languages는 아래 리스트를 가리킨다.
second_languages
['C++', 'C#', '자바스크립트', 'Node.js']
변수 lang가 가리키는 문자열이 second_languages가 가리키는
리스트 포함되어 있지 않은 경우에만 언급된 언어가
오른편 끝에 추가된 리스트를 화면에 출력하는 코드를 작성한다.
힌트: not in 연산자 활용
답:
if ... 명령문을 이용한다.
이때 if 다음에 오는 진리값을 표현하는 식으로 리스트를 대상으로 항목이 아닌경우에
True로 계산되는 not in 연산자를 이용한다.
또한 리스트의 + 연산을 이용한다.
예제: 새로운 언어를 사용하는 경우
lang = '파이썬'
if lang not in second_languages:
print(second_languages + [lang])
['C++', 'C#', '자바스크립트', 'Node.js', '파이썬']
예제: 이미 포함된 언어를 사용하는 경우엔 아무 것도 하지 않음.
lang = 'Node.js'
if lang not in second_languages:
print(second_languages + [lang])
예제 7
변수 greetings가 다음과 같이 선언된다.
greetings = '파이썬, 안녕!'
(1) 문자열에 포함된 쉼표 기호 ,를 확인하는 인덱싱을 표현하는 수식을 정의하라.
답:
greetings[3]
','
(2) 문자열에 포함된 느낌표 기호 !을 확인하는 인덱싱을 표현하는 수식을 정의하라.
답:
greetings[-1]
'!'
예제 8
우유 가격은 820원이고, 아이스크림 가격은 1500원이다. 아이스크림은 3개 이상 구입하면 5% 할인해준다. 우유 2개와 아이스크림 3개를 구입할 때 지불해야 하는 가격을 다양한 변수를 활용하여 계산하는 코드를 작성한다.
힌트: 할인율이 5%이면 할인을 적용할 때 구입 가격에 (1 - 0.05)를 곱한다.
답:
우유 가격과 개수, 아이스크림 가격과 개수, 할인율을 변수로 활용해서 간단한 연산을 실행한다.
milk_price = 820
icecream_price = 1500
discount = 0.05 # 아이스크림 3개 이상 구입시 할인율
milk = 2
icecream = 3
할인을 받을 수 있는 경우와 그렇지 않은 경우를
구분해서 코드를 실행할 수 있다.
이를 위해 if ... else ... 조건문을 이용한다.
최종 가격은 정수로 지정한다.
이유는 할인을 적용하면 즉, 할인율을 곱하면 부동소수점으로 계산되기 때문이다.
if icecream < 3:
total_price = milk_price * milk + icecream_price * icecream # 할인 없음
else:
total_price = milk_price * milk + icecream_price * icecream * (1-discount) # 할인 적용
print("우유", milk, "개", "아이스크림", icecream, "개", "가격:", int(total_price), "원")
우유 2 개 아이스크림 3 개 가격: 5915 원
예제 9
연이자 5%인 정기예금에 1천만원을 10년간 은행에 맡겼을 때 10년 후에 수령할 금액을 계산하는 코드를 다양한 변수를 활용하여 구현한다. 단, 다음 형식으로 출력하라.
10년 후 받을 원금 + 이자는 OOO 원입니다.
원리합계 계산은 아래 식을 따른다.
원리합계 = 원금 * (1 + 연금리 * 기간)
힌트:
아래 변수를 활용해서 원리합계 수식을 간단하게 구현할 수 있다.
principal = 원금
rate = 연이자율
period = 저축기간(년)
savings = 원리합계
답:
principal = 10000000
rate = 0.05
period = 10
savings = principal * (1 + rate * period)
print("10년 후 받는 원금 + 이자는", savings, "원입니다.")
10년 후 받는 원금 + 이자는 15000000.0 원입니다.
3.5. 연습문제#
(연습) 값과 연산에 포함된 문제들을 풀어보세요.