Think Python의 2장 내용을 요약 및 수정한 내용입니다.
변수는 특정한 값을 가리키도록 하는 도구이며, 기본 역할은 두 가지이다.
변수 할당은 변수가 특정 값을 가리키도록 하는 것을 의미하며 명령형 프로그래밍의 기본 명령문 중의 하나이며, 아래의 형식으로 사용된다.
변수 = 표현식
예를 들어, 아래 세 개의 할당 명령문은 특정 변수에 특정 표현식을 지정하는 기본적인 방식을 보여준다.
message = '이제부터 변수 할당 명령문을 다룹니다.'
n = 17
pi = 3.1415926535897932
위 명령문을 실행하면
message
는 '이제부터 변수 할당 명령문을 다룹니다.' 라는 문자열을, n
는 정수 17을pi
는 원주율 $\pi$에 해당하는 값을각각 가리킨다.
변수가 가리키는 값은 프로그램 실행과정에서 달라질 수 있다.
예를 들어, 변수 n
에 18을 새롭게 할당할 수 있다.
n = 18
그러면 이제부터는 n
은 저웃 18처럼 다룰 수 있다.
print(n - 1)
변수 할당은 컴퓨터 메모리 상에서 이루어지며, 변수들과 변수들에 할당된 값들 사이의 관계는 프레임(frame)을 통해 관리된다. 즉, 변수 할당 명령문을 실행하면 컴퓨터 메모리 상에서 변수들과 변수들에 할당된 값들 사이의 관계에 변화가 발생하며, 이는 프레임에 변화를 초래한다.
컴퓨터 메모리 상에서 일어나는 변화를 사람이 직접 눈으로 볼 수는 없다. 하지만 파이썬튜터가 프레임의 변화를 시각적으로 보여주는 기능을 지원한다. 앞서 변수 세 개의 할당을 실행하면 프레임이 어떻게 변화하는지를 pythontutor.com에 접속해서 확인할 수 있다.
파이썬튜터 사용법은 다음과 같다.
변수의 이름을 정할 때 할당되는 값과 연관된 이름으로 정하는 것이 좋으며, 아무리 길어도 상관 없다. 다만 아래의 제한 사항을 지키지 않으면 오류가 발생한다.
_
) 등을 사용한다.@
)와 물결 기호(~
)는 사용할 수 없다.사용하면 안되는 사례 몇 가지를 살펴보자.
7trombones = 'big parade'
big number = 1000000
class
는 파이썬에서 클래스를 선언할 때 사용되는 특수한 기능을 갖는다.
클래스는 이후에 다룬다.class = 'Advanced Theoretical Zymurgy'
파이썬의 지정어들은 다음과 같다.
False class finally is return
None continue for lambda try
True def from nonlocal while
and del global not with
as elif if or yield
assert else import pass
break except in raise
소문자와 대문자는 엄연히 구분된다.
예를 들어, 'hello'
와 Hello
는 서로 다른 문자열이다.
'hello' == 'Hello'
변수 이름은 소문자로 시작하는 게 관습이다. 대문자로 시작하는 이름은 주로 클래스를 선언할 때 사용한다.
정수, 실수, 문자, 문자열, 진리값, 리스트, 튜플, 사전 등 프로그램이 다루는 가장 기본적인 대상을 값(value)이라 부른다. 예를 들어, 1, 2, 3.2, 'Hello, World!' 등이 지금까지 이 수업에서 본 값들이다.
모든 값들은 자신들만의 자료형을 갖는다. 예를 들어,
int
)이고,float
) 자료형이고,만약 값이 어떤 자료형에 속하는지 모르겠다면 아래와 같이 확인한다.
type(1)
type(3.2)
type('Hello, World!')
숫자를 표기할 때 다음 세 가지 사항들에 주의해야 한다.
첫째, '17'
, '3.2'
등은 숫자처럼 보이지만 따옴표로 둘러싸여 있으며,
숫자가 아닌 숫자 기호로 이루어진 문자열이다.
type('17')
type('3.2')
둘째, 숫자를 적을 대 쉼표(콤마)를 사용하면 안된다. 쉼표는 파이썬에서 특수한 역할을 수행한다. 나중에 튜플 자료형에서 쉼표의 역할을 다룰 것이다.
예를 들어, 1,000,000
이라고 입력하면 백만이 아니라 1과 0과 0을 항목으로 갖는
길이가 3인 튜플 자료형으로 인식된다.
튜플은 여러 개의 값을 하나로 묶어서 사용하는 값들의 자료형이며
나중에 자세히 다룬다.
not_a_number = 1,000,000
print(not_a_number)
실제로 not_a_number
의 지료형은 튜플이다.
type(not_a_number)
셋째, 숫자는 0으로 시작하면 안된다.
# 청와대 우편번호
zipcode = 03048
우편번호는 연산이 아니라 구역 식별용으로 사용되기에, 고유명사처럼 문자열로 처리하는 것이 좋다.
# 청와대 우편번호
zipcode = '03048'
변수의 자료형은 가리키는 값의 자료형을 사용한다. 따라서, 변수의 자료형은 할당된 값이 수정되면 함께 수정된 값의 자료형을 갖는다.
x = 18
type(x)
x = 3.14
type(x)
함수는 특정 기능을 수행하는 코드에 이름을 붙힌거라고 생각할 수 있다. 연산자는 사칙연산 등 숫자들을 이용하여 계산을 하는 함수를 가리키는 의미로 사용한다. 함수에 대한 엄밀한 정의는 이후에 다룬다.
여기서는 지금까지 살펴 본 코드에서 사용된 함수들의 기능을 확인한다.
+
), 뺄셈(-
), 곱셈(*
), 나눗셈(/
)<
), 크다(>
), 작거나 같다(<=
), 크거나 같다(>=
)input
: 사용자가 키보드로 입력한 값을 받아 문자열로 처리하여 내준다(return).print
: 인자로 지정된 값을 화면에 출력한다.int
: 정수 모양의 문자열을 진짜 정수로 변환해서 내준다.type
: 인자로 지정된 값의 자료형을 내준다.함수는 실행되면 지정된 코드를 실행한다. 실행이 영원히 멈추지 않을 수도 있다. 하지만 일정 시간이 지나 멈춘다면 특정 값을 내준다(리턴한다). '내준다'의 영어 표현은 리턴(return)이라서 함수가 내주는 값을 리턴값이라고도 부른다.
None
값¶print
함수는 어떠한 값도 계산하지 않으며, 단순히 지정된 값을 화면에 출력한다.
이런 경우 내주는 값은 None
이 된다.
None
은 "아무 의미도 없는 값"을 나타내는 값이며,
어떤 용도로도 사용하지 못한다.
암튼 파이썬에서 사용되는 함수는 실행이 멈추면 무조건 특정 값을 내준다는 사실은 기억해 두어야 한다.
print
함수는 지정된 값을 화면에 출력한 후 None
이라는 값을 내준다.
그런데 화면에 출력된 값은 print
함수가 내주는 값과 아무 상관이 없다.
이렇게 함수가 실행되는 과정에서 내주는 값과 상관 없이 하는 일을 부수효과(side effect)라 부른다.
즉, print
함수가 실행될 때 화면에 출력된 값은 print
함수의 부수효과의 결과이다.
이 점에 주의하면서 아래 코드를 살펴보자.
print(print(1), print(2))
위 코드의 실행결과에 대한 설명은 다음과 같다.
print
함수의 인자는 print(1)
과 print(2)
이다.print(1)
을 실행할 때 내주는 값은 None
이다.
print(2)
또한 동일하다.print(None, None)
을 실행하게 된다. print(1)
을 실행할 때 1
을 먼저 화면에 출력하고,
print(2)
를 실행할 때 2
를 먼저 화면에 출력한다.1
, 2
, None None
순서로 화면에 출력된다.print(None, None)
의 실행결과는 None
인데,
None
은 아무 의미도 없는 값이기 때문에 달리 보여지지 않는다.파이썬에서는 함수도 하나의 값으로 간주된다. 이렇게 하나의 값으로 간주되는 대상을 제1종 객체(first-class object)라고 부른다. 제1종 객체로 간주되는 값은 변수에 할당되거나, 함수의 인자 또는 리턴값으로 사용될 수 있다.
함수를 인자로 받거나 내주는 값으로 사용하는 함수를 고계 함수(higher-order function)라 부른다.
덧셈 기호 +
와 곱셈 기호 *
는 숫자뿐만 아니라 문자열에 대해서도
작동하는 연산자이다.
물론 숫자들의 덧셈, 곱셈과는 다르게 작동한다.
주의: 뺄셈 기호('-'
)와 나눗셈 기호('/'
)는 문자열 연산자로 사용되지 않는다.
덧셈 기호는 두 문자열을 이어붙일 때 사용한다.
first = '파이썬, '
second = '안녕!'
print(first + second)
문자열을 정수와 곱하면 해당 문자열을 정수만큼 복제하여 모두 이어붙인다.
'spam'*3
'I love you! '*4
표현식(expression)은 '값을 나타내는 식'이며 값, 변수, 함수 등을 규칙에 맞게 조합하여 만든다.
예를 들어, 만약에 변수 x
에 할당된 값이 정수 3
이라고 가정한다.
아래 표는 표현식과 해당 표현식이 표현하는 값, 그리고 값의 자료형 사이의 관계를 보여준다.
표현식 | 값 | 자료형 |
---|---|---|
17 |
17 |
int |
"abc" |
"abc" |
str |
x |
3 |
int |
x/2 |
1.5 |
float |
(x/2 - 1) < 0 |
False |
bool |
(1, x/2-1, x+x+1) |
(1, 0.5, 7) |
tuple |
[x, x*3/2, x**3+1] |
[3, 4.5, 28] |
list |
print(x) |
None |
NoneType |
int('17') |
17 |
int |
input |
input |
method |
None
의 자료형은 NoneType
이다.input
함수는 자체로 하나의 값이다.
input
함수의 자료형은 method
라고 한다. type(input)
표현식이 나타내는 값은 파이썬 해석기에 의해 계산된다. 계산 과정에서 연산자 별로 지정된 우선순위를 따른다. 사칙연산 등 많이 사용되는 수학 함수들의 우선순위는 일반적으로 알려진 것과 동일하다.
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 = 8
60/2*3 = (60/2)*3 = 30*3 = 90
2**3**2 = 2**(3**2) = 2**9 = 512
컴퓨터에 의해 실행될 수 있는 문장을 명령문이라 부른다. 프로그래밍 언어에 따라 명령문 작성 규칙이 정해져 있다. 명령문들을 규칙에 맞게 적절히 구상하여 원하는 프로그램을 구현한다.
명령문은 기본 명령문들을 조합해서 생성된다. 지금까지 살펴본 기본 명령문들은 다음과 같다.
print
while
반복문위 명령문들만을 이용하여 숫자맞히기 게임을 구현하였다.
print("숫자맞추기 게임에 환영합니다.")
secret = 9
guess = -1
while guess != secret:
guess = int(input("0부터 20 사이의 숫자 하나를 입력하세요: "))
if guess == secret:
print("맞았습니다!")
elif guess > secret:
print("너무 커요!")
else:
print("너무 작아요!")
print("게임 종료!")
튜링기계(Turing machine)는 계산을 기계적으로 다루기 위한 수학적 모형의 일종이며, 1936년에 튜링(A. Turing)이 고안한 가상장치이다. 튜링기계에 대한 자세한 소개는 위키피디아: 튜링기계를 추천한다.
앞서 언급된 기본 명령문들만으로도 파이썬 프로그래밍 언어가 충분히 강력하다. 여기서 충분하다는 의미는 기존에 알려진 가장 강력한 프로그래밍 언어와 동급이란 의미이다. 보다 전문적으로 튜링 완전(Turing complete)하다라고 말하며, 이는 튜링기계와 원칙적으로 동일한 성능을 갖는다 것을 의미한다.
for
반복문 등과 같은 다른 기본 명령문들이 있다.
하지만 프로그래밍의 편의성을 높이는 데에 유용하지만 이론적으로 더 강력한
프로그래밍 언어를 만들지는 못한다.
즉, 튜링 완전성을 벗어나지는 못한다.
어떤 프로그래밍 언어도 튜링 완전성 이상의 성능을 내지 못한다는 주장이 있다. 즉, 미래의 어떤 컴퓨터도 튜링 완전성을 뛰어 넘지 못할 것이다 라는 주장이며 이를 처치-튜링 테제(Church-Turing thesis)라고 부른다. 처치-튜링 테제는 하나의 주장이다. 왜냐하면 미래에 어떤 종류의 컴퓨터가 출현할지 모르기 때문이다. 하지만 현 시점까지는 튜링 완전성을 뛰어 넘는 컴퓨터나 프로그래밍 언어는 존재하지 않았다.
앞서 언급한 튜링 완전성은 약간 오해의 소지가 있다. 왜냐하면 튜링기계가 완전하다, 즉, 모든 문제를 해결할 수 있다라는 생각을 하게 만들기 때문이다. 하지만 튜링 완전성은 다른 기계 또는 프로그래밍 언어가 튜링 기계와 이론적으로 동일한 능력을 보유한다라는 의미이지, 튜링기계가 완전하다는 의미가 아니다.
실제로 튜링기계는 완전하지 않으며, 튜링기계의 불완전성은 튜링 자신이 소위 정지문제(halting problem)로 알려진 문제의 답을 내려는 시도 과정에서 증명하였다. 정지문제에 대한 쉽고 재밌는 설명은 한글자막이 지원되는 유튜브 동영상 컴퓨터가 모든 것을 해결할 수 없다는 증명 (정지 문제)에서 들을 수 있다.
프로그램 코드 중간중간에 사용된 명령문과 관련된 설명을 적어 놓으면 코드를 보다 쉽게 이해할 수 있게 된다. 이와 같이 코드의 실행과 무관한 설명 문장을 주석(comment)이라 부르며, 코드가 실행될 때 파이썬 해석기에 의해 무시된다.
#
, 샵)로 시작하며
#
이후의 문장은 실행과정에서 무시된다.# speed는 시속을 가리키는 변수이다.
speed = 90 # 속도 단위는 km이다.
'''
)로 감싼다.print(0)
'''
여러 줄 주석은
이렇게 사용합니다.
'''
print(1)
변수 이름으로 class
등의 지정어를 사용하거나, odd~job
나 US$
처럼
허용되지 않은 문자나 기호를 포함하는 경우에 파이썬 해석기는 오류를 발생시키며 프로그램의 실행을 멈춘다.
예를 들어, 아래와 같이 변수 이름에 공백을 사용하여 실행한 결과를 확인해 보자.
bad name = 5
이와 같이 오류가 발생하면 오류의 원인을 찾아 해결해야 한다. 이렇게 프로그램의 오류를 찾아 해결하는 과정을 디버깅(debugging)이라 부른다.
프로그램의 오류는 크게 세 가지 유형이 있다.
변수 이름을 잘못 지정하는 경우 위와 같이 구문 오류(SyntaxError: invalid syntax
)가 발생한다.
구문 오류는 해석기가 프로그램을 실행하기 전에 일종의 문법 검사를 통해 찾아낸다.
런타임 오류는 구문 오류를 포함하지 않는 프로그램이 실행되는 과정에서 발생하는 오류이다. 런타임 오류는 다양한 경우에 발생한다. 여기서는 두 가지 경우를 살펴본다.
런타임 에러의 또다는 대표적인 예는 0으로 나누기 오류이다.
num = 0
print(3/num)
ZeroDivisionError
라고 표시되는데,
이는 0으로 나눗셈을 시도하는 경우 발생한다.
num
변수가 가리키는 값과 3 모두 정수이고,
나눗셈 연산자는 정수들을 대상으로 작동하도록 정의되었기 때문에
0/num
은 문법적으로 전혀 문제가 없다.
하지만 실제로 실행을 하다보면 num
에 할당된 값이 0이라는 것으로 확인되어
오류를 발생시키는 것이다.
예를 들어 아래 코드에는 문법적인 오류가 없다. 하지만 실행을 하면 'a_number' 라는 이름이 선언되어 있지 없기 때문에 문제가 발생한다.
a_Number = 327.68
b = a_number * 3
자세히 살펴보면 'a_number'와 'a_Number' 둘 중에 하나는 오타임을 알 수 있다.
프로그램이 실행은 되지만 원하는 기능을 지원하지 못한다면 프로그램을 제대로 구현하지 못한 것이다. 프로그램은 작동하기 때문에 구문 오류나 런타임 오류와는 달리 원인을 바로 확인하기 어려울 수 있다. 이와같은 오류를 의미 오류(semantic error)라 부르며, 발생원인은 매우 다양하다.
수학 문제를 풀다가 계산실수를 하거나, 기호를 다르게 적거나, 문제를 잘못 이해했거나 해서 풀 수 있었던 문제를 틀렸던 경험이 있을 것이다. 프로그래밍 과정에서도 유사한 실수를 수업이 하게 된다.
예를 들어, 아래 프로그램은 두 배 계산 대신에 제곱 계산을 하는 실수를 보여준다.
num = int(input("숫자를 입력하세요: "))
doubleNum = num**2
print("입력한 값의 두 배는", doubleNum, "입니다.")
두 배하려면 num*2
를 사용했어야 하는데 실수로 num**2
를 사용하여서
결과적으로 입력한 값의 제곱을 계산하게 된다.
수천, 수만 줄로 이루어진 코드에서 이런 형식의 오류의 원인을 찾는 일은
경우에 따라 잔디밭에서 바늘찾기처럼 어렵거나 불가능할 수 있다.
아래 명령문들을 실행하였을 때 무슨 일이 발생하는지를 확인하라.
print("Hello World"
print("Hello World)
print('Hello World")
print(+2)
print(2++2)
print(023)
print(21 8)
변수 선언과 할당 관련 주의해야할 점들을 다룬다. 아래 명령문들을 실행하였을 때 무슨 일이 발생하는지를 확인하라.
23 = n
x = y = 1
x = 2;
y = x + 1.
z = x y
아래와 같이 변수들이 선언 및 할당되었다고 가정하자.
width = 17
height = 12.0
delimiter = '.'
다음에 오는 각각의 표현식들에 대해, 표현식의 값과 (표현식의 값이 갖는) 자료형을 확인하라.
width//2
width/2
width/2.0
height/3
1+2*5
delimiter*5
파이썬을 계산기처럼 사용할 수 있다.
print
함수의 성질을 조사한다.
즉, print
함수가 받아들일 수 있는 인자와 리턴값에 대해 알아본다.
설명을 예를 들면서 하면 더욱 좋다.
(힌트: help(print)
명령문을 실행하면 print
함수에 대한 기초정보를 확인할 수 있다.)