2013년 7월 3일 수요일

Python 기초 지식

 여기에서는 Python의 기초인 할당, 표현식, 숫자나 문자열을 type, code 주석 등등을 설명할 것이다. 처음은 다른 주요 language와 차이를 보이는 Python의 code block 구조에 대해서 알아보자.

들여쓰기와 block 구조

 Python은 다른 대부분의 programming language들과는 다르게 공백과 들여쓰기를 사용하여 block 구조를 정의한다. (즉, else 조건절 등과 같은 loop의 몸체를 구성하는 것은 공백과 들여쓰기를 사용하여 정의하는 것이다.) 대부분의 language들은 중괄호와 같은 것들로 block의 구조를 정의하고 있다. 다음은 9를 factorial 연산을 하여 결과값을 r로 표현하는 C code이다.

/* C code 예제 */
int n, r;
n = 9;
r = 1;
while (n > 0) {
    r * = n;
    n--;
}

 중괄호 {} 가 code에서 반복 loop를 실행하는 while loop 몸체의 범위를 정하고 있다. code는 일반적으로 위의 예제에서 처럼 들여쓰기를 하면 가독성을 높일 수 있다. 하지만 다음과 같이 작성도 가능하다.

/* 임의의 들여쓰기로 작성된 C code 예제 */
    int n, r;
        n = 9;
        r = 1;
    while (n > 0) {
r *= n;
n--;
}

이 code는 읽기 어렵게 작성되어있더라도 정상적으로 동작될 것이다.
다음은 동일한 기능을 하는 Python code 이다.

# Python code 예제
n = 9
r = 1
while n > 0:
    r = r * n    # Python은 C-style인 r *= n도 지원한다.
    n = n - 1    # Python은 n -= 1도 지원한다.

 Python은 code 구조를 나타내기 위해서 중괄호 대신 들여쓰기를 사용한다. 위의 code에서 마지막 두 line은 while loop의 몸체이며 이는 while 문장 다음에 위치하여 한 단계 높은 들여쓰기로 구분된다. 이 두 line에 들여쓰기가 없다면 while loop의 몸체로 인식하지 않을 것이다.
 중괄호 {} 대신에 들여쓰기를 사용하는 것이 익숙하지 않을 수 있지만 여기에는 중요한 이점이 존재한다.
중괄호 {}를 빼먹거나 더 사용하여 발생하는 문제가 없어진다. 이로 인해 당신이 code에서 중괄호의 짝을 맞추기 위해 아래에서 위까지 검사하는 일은 없을 것이다.
code의 시각적인 구조는 실제 구조를 반영한다. 이는 보이는 그대로 code의 뼈대를 잡는데 수월함을 준다.
Python coding style에 일반적인 일관성을 부여한다. 다르게 말하자면 당신이 다른 누군가의 주관적인 미학으로 작성된 code를 이해하는데 어려움을 겪는 일이 없어진다는 것이다. 다른 사람이 작성한 code도 당신이 작성한 code와 거의 유사할 것이다.

 당신은 아마도 code를 작성하면서 이미 일관된 들여쓰기를 사용하고 있을 것이므로 이 특징을 이해하는데 큰 어려움은 없을 것이다. 만약 IDLE을 사용한다면 자동으로 line에 들여쓰기를 할 것이다. IDLE 사용시에 들여쓰기 단계를 벗어나려면 backspace를 입력하기만 하면 된다. Emacs, VIM, Eclipse 등의 programming editor들이나 IDE들도 이 기능을 제공한다. Python interpreter의 prompt에 명령어를 입력하기 전에 공백이 입력되었다면 error message가 표시되는 것을 볼 수 있다. 이와 같은 들여쓰기에 대한 실수를 한두 번씩 할 수 있으니 이 특징에 익숙해져야 한다.

주석 표현의 차이점

 보통 Python file 내에서 # 기호 다음에 오는 것들은 주석으로 인식되어 language에서 무시된다. 단 문자열 내의 # 기호는 예외로 문자열을 구성하는 문자로 처리된다.

# x에 5를 할당
x = 5
x = 3    # 이제 x는 3이다.
x = “# 이것은 주석이 아님”

Python code 내에 주석을 빈번하게 넣게 될 것이다.

변수와 할당

 다른 language들과 마찬가지로 Python에서 가장 일반적으로 사용되는 명령은 할당이다. x라는 변수에 5를 할당하는 Python code는 다음과 같다.

x = 5

 다른 computer language들과는 달리 Python에서는 변수 type 정의와 end-of-line 구분자를 필요로 하지 않는다. line이 끝나면 end-of-line이 선언되며 변수들은 처음 할당 시에 자동으로 생성된다.
 C나 다음 language들의 변수들과는 다르게 Python 변수들은 선언된 값의 type만 저장되어 어떤 object로도 지정이 가능하다. 다음 Python code는 완전히 적법한 code이다.

>>> x = “Hello”
>>> print(x) Hello
>>> x = 5
>>> print(x)
5

 x는 처음에 문자열 object “Hello”를 참조한 후에 정수 object 5를 참조한다. 물론 이 기능을 남용하여 동일한 변수명에 연속하여 다른 data type들을 참조하도록 제멋대로 할당하는 것은 이해하기에 혼란스러운 code를 만들 수 있다.
 신규 할당은 기존의 할당을 무시한다. del 구문은 변수를 삭제한다. 변수를 삭제한 후에 변수의 내용을 출력하려고 하면 생성되지 않았던 변수를 출력하는 결과와 동일한 error를 발생시킨다.

>>> x = 5
>>> print(x)
5
>>> del x
>>> print(x)
Traceback (most recent call last):
File “<stdin>”, line 1, in <module>
NameError: name 'x' is not defined 
>>>

 위의 예제에서는 error가 발생되면서 exception으로 불리는 traceback message가 출력되었다. 마지막 line은 x에 대해서 NameError exception의 감지를 알려주고 있다. x를 삭제하면 x는 더 이상 유효한 변수명이 아니게 된다. 이 예제에서 trace는 line 1, in <module> 만 반환하는데, 이는 대화식 mode에서 단지 한 line만 전송되었기 때문이다. 일반적으로 오류 발생 시에 기존 함수 호출의 동적 호출 구조가 반환된다. 만약 당신이 IDLE을 사용한다면 약간의 차이는 있겠지만 다음과 같은 정보를 받게 될 것이다.

Traceback (most recent call last):
    File “<pyshell#3>”, line 1, in <module>
        print(x)
NameError: name 'x' is not defined

이 mechanism에 대해서는 추후에 더욱 자세하게 설명할 기회를 가질 수 있도록 하겠다. 발생할 수 있는 exception들의 전체 list와 이 exception들을 발생시키는 것들에 대한 내용은 Python reference site(http://docs.python.org/2/library/exceptions.html#bltin-exceptions)에서 확인할 수 있다.
 변수명은 대・소문자를 구분한다. 그리고 숫자와 문자, underline(_)으로 구성될 수 있으며, 문자나 underline(_)으로 시작되어야 한다.

표현식

 Python은 산술 표현식을 지원한다. 다음 code는 3과 5의 평균을 계산하고 변수 z에 결과값을 할당한다.

x = 3
y = 5
z = (x + y) / 2

 Python은 type 강제 변환 측면에서 C의 산술 규칙과는 다르다는 것을 주의하기 바란다. 정수들만 포함된 산술 연산은 언제나 정수를 반환하지는 않는다. (Python 3부터) 모든 값들이 정수인 나눗셈 연산에서는 부동 소수점 값을 반환하며 소수 부분을 버림하지 않는다. 소수 부분을 버림한 정수를 반환하는 기존의 나눗셈 연산을 하려고 한다면 //를 사용해야 한다.
 만약 마지막 line에서 괄호를 제거한다면 연산자 우선 순위의 표준 규칙이 적용되므로 “x + (y / 2)”로 계산될 것이다.
 표현식은 숫자값에만 사용되는 것이 아니다. 문자열, Boolean 값 등의 다양한 다른 object type들에도  다양한 방식으로 표현식이 사용될 수 있다는 것을 알아두기 바란다.

Strings(문자열)

 Python은 다른 대부분의 programming language들과 마찬가지로 문자열을 큰따옴표를 사용하여 문자열을 표현한다. 다음 line은 변수 x에 “Hello, World” 문자열을 할당한다.

x = “Hello, World”

backslash(\)는 특수한 의미를 가지는 escape 문자로 사용할 수 있다. \n은 개행 문자, \t는 tab 문자, \\는 단일 backslash(\) 문자, \”는 일반 큰따옴표 문자. 다음과 같이 사용할 수 있다.

x = “\t이 문자열은 \”tab\”으로 시작된다.”
x = “이 문자열은 단일 backslash(\\)를 포함한다.”

 큰따옴표 대신 작은 따옴표를 사용할 수도 있다. 다음 두 line은 동일하게 동작한다.

x = “Hello, World”
x = ‘Hello, World’

 단지 차이점은 작은 따옴표 내에서는 “ 문자를 backslash(\) 없이 사용할 수 있고, 큰 따옴표 내에서는 ‘ 문자를 backslash(\) 없이 사용할 수 있다는 점이다.

x = “Don’t need a backslash”
x = ‘Can\’t get by without a backslash’
x = “Backslash your \” character!”
x = ‘You can leave the “ alone’

 일반적인 문자열은 line을 나눌 수가 없다. 이 code는 동작되지 않는다.

# 이 Python code는 ERROR를 발생시킨다. -- 문자열은 line을 분리할 수 없다.
x = “개행 문자를 사용하지 않고 문자열의 line을 이렇게 
변경하려고 하는 것은 잘못된 시도이다.”

 하지만 Python에서는 삼중 따옴표 문자열을 사용하면 line 변경, backslash(\) 없이 작은 따옴표와 큰 따옴표를 사용할 수 있다.

x = """삼중 따옴표를 사용하여 문자열을 묶어주면 
line 변경을 할 수 있으며 “ 문자와 ‘ 문자도 backslash 
없이 사용할 수 있다. """

 위의 code에서 x는 """ 구분자들 사이에 있는 전체 문장을 값으로 할당받는다.(큰 따옴표 대신에 작은 따옴표를 삼중으로 사용해도 동일하다.)

숫자

 Python은 네 가지 종류(integer-정수, float-부동소수점, complex number-복소수, Boolean)의 숫자형을 제공한다. integer는 정수(0, -11, +33, 123456)로 작성되며 범위는 제약이 없지만 실행되는 machine의 자원에 의해 제한된다. float(부동소수점)은 소수점(3.14, 2.718281828)이나 과학적 기수법(-2E-8)으로 표현될 수 있다. 이 값들의 정밀도는 machine architecture에 의해 좌우되지만 일반적으로 C의 (64-bit) double 형과 동일하다. complex number(복소수)는 추후에 따로 다루도록 하겠다. Boolean은 True/False나 문자열이 아닌 1/0으로 표현된다.
 산술 연산은 C와 무척 유사하다. 두 정수를 연산하면 정수를 반환하지만 나눗셈(/)은 부동 소수점 숫자값을 반환한다. // 나눗셈 기호를 사용하면 소수 부분을 버림한 정수를 반환한다. 부동 소수점 숫자값들을 연산하면 항상 부동 소수점 숫자값들을 반환한다. 다음은 몇 가지 예제들이다.

>>> 5 + 2 - 3 * 2 1
>>> 5 / 2    # 일반 나눗셈은 부동 소수점 숫자값을 반환한다.
2.5
>>> 5 / 2.0    # 마찬가지로 부동 소수점 숫자값을 반환
2.5
>>> 5 // 2    # '//'를 사용하면 소수 부분을 버림한 정수를 반환
2
>>> 30000000000    # 다른 language들에서는 이 값이 int 범위를 넘어설 수도 있다.
30000000000
>>> 30000000000 * 3
90000000000
>>> 30000000000 * 3.0
90000000000.0
>>> 2.0e-8    # 과학적 기수법은 부동 소수점 숫자값을 반환한다.
2e-08
>>> 3000000 * 3000000
9000000000000
>>> int(200.2)    # <<== ※1
200
>>> int(2e2)    # <<== ※1
200
>>> float(200)    # <<== ※1
200.0

 ※1 부분은 형변환을 수행한 것이며 int는 소수 부분을 버림한 값을 반환한다.
 Python의 숫자값은 C나 Java와 비교하여 두 가지 이점을 가지고 있다. 첫 번째는 정수값의 표현범위가 훨씬 크며, 두 번째는 정수들을 나눗셈하면 부동 소수점 숫자값을 반환하는 것이다.

내장 숫자 함수들

 Python은 다음의 core 숫자 함수들을 제공한다.

abs, divmod, cmp, coerce, float, hex, int, long, max, min, oct, pow, round

상세 사항은 documentation을 참조하라.

고급 숫자 함수들

 삼각법과 쌍곡선 삼각법 함수, 상수 등과 같은 고급 숫자 함수들은 Python에 내장되어 있지는 않지만 math라는 표준 module에서 제공하고 있다. module들에 대해서는 추후에 설명하도록 하겠다. 지금은 여기에서 설명하는 math 함수들은 Python program 상단이나 대화식 session에서 다음 구문을 입력하여 사용할 수 있다는 것을 알아두기 바란다.

from math import *

 math module은 다음 함수들과 상수들을 제공한다.

acos, asin, atan, atan2, ceil, cos, cosh, e, exp, fabs, floor, fmod, frexp, hypot, ldexp, log, log10, mod, pi, pow, sin, sinh, sqrt, tan, tanh

상세 사항은 documentation을 참조하라.

숫자 연산

 core Python은 속도 제한사항으로 인해 집중적인 숫자 연산 program에 적합하지는 않다. 하지만 강력한 Python extension인 NumPy는 많은 숫자 연산에 고효율 implementation들을 제공하고 있다. 이 extension은 다차원 행렬과 Fast Fourier Transfrom과 같은 고급 함수들을 포함하는 array 연산에 특화되어 있다. NumPy는 www.scipy.org에서 사용할 수 있다.

복소수(Complex Number)

 복소수는 nj 표현식(n은 정수나 부동 소수점 숫자)이 나오면 자동적으로 생성된다. 물론 허수의 표준 engineering 표기법은 -1의 제곱근과 동일하다. 다음은 그 예제이다.

>>> (3+2j)
(3+2j)

 Python은 복소수를 괄호를 사용하여 표현한다. 이는 단일 object 값을 screen에 출력하는 방식이다.

>>> 3 + 2j - (4+4j)
(-1-2j)
>>> (1+2j) * (3+4j)
(-5+10j)
>>> 1j * 1j
(-1+0j)

j * j 연산은 -1 값을 반환하지만 결과값은 Python 복소수 object라는 것을 주의하라. 복소수는 절대 자동으로 동일한 실수나 정수 object로 변환되지 않는다. 하지만 real과 imag를 사용하여 실수 부분과 허수 부분에 쉽게 접근할 수 있다.

>>> z = (3+5j)
>>> z.real
3.0
>>> z.imag
5.0

 복소수의 실수와 허수 부분은 항상 부동 소수점 숫자 형태로 반환된다는 것을 주의하라.

고급 복소수(complex-number) 함수들

 math module 내의 함수들은 복소수에 적용할 수 없다. 근본적인 이유는 대부분의 사용자들이 -1의 제곱근을 연산하면 답이 아니라 error를 생성하기를 바란다는 것이다. 대신 복소수를 연산할 수 있는 유사 함수들을 cmath module에서 제공하고 있다.

acos, acosh, asin, asinh, atan, atanh, cos, cosh, e, exp, log, log10, pi, sin, sinh, sqrt, tan, tanh

 특수 목적 복소수 함수들을 code 내에서 명확하게 하고 일반적 상황에서 동일하게 동작하는 함수들의 이름과 충돌을 피하기 위해서 다음과 같이 cmath module을 import 하는 것이 좋다.

import cmath

이후에는 해당 함수를 사용 시에 명확하게 cmath package를 참조하도록 기재한다.

>>> import cmath
>>> cmath.sqrt(-1)
1j

 여기서 기억할 것은 cmath module을 import하면 다른 숫자형에서 가능한 연산들을 거의 다 할 수 있다는 것이다.

None 값

 string과 number 같은 표준 type에 추가로 Python은 None이라는 단일 특수 data object가 정의된 특수 기본 data type을 가지고 있다. 이름에서 알 수 있듯이 None은 빈 값을 나타내는데 사용된다. 이 data type은 Python 도처에서 다양한 모습으로 나타난다. 예를 들면 명확하게 값을 반환하지 않는 함수인 Python procedure는 기본적으로 None을 반환한다.
 Python programming에서 None은 종종 의미있는 data를 찾지 못하거나 아직 연산되지 않은 data의 구조를 나타내는 대체 data object로 유용하게 사용된다. 당신은 None의 존재를 쉽게 test 할 수 있다. Python system 전체에서 None 객체는 유일하며, (None에 대한 모든 참조는 동일한 object를 가르킨다.) None과 동일한 object는 존재하지 않기 때문이다.

사용자 입력값

 input() 함수를 사용하여 사용자로부터 값을 입력 받을 수 있다. input의 parameter로 사용자에게 표시할 prompt 문자열을 사용할 수 있다.

>>> name = input("Name? ")
Name? Vern
>>> print(name)
Vern
>>> age = int(input("Age? "))    # 입력값을 문자열에서 정수로 변환
Age? 28
>>> print(age)
28
>>>

이 함수를 통해 사용자로부터 상당히 단순하게 값을 입력받을 수 있다. 여기서 주의할 점은 입력값은 문자열이라는 것이다. 따라서 입력값을 숫자로 처리하려면 반드시 int()나 float() 함수를 사용하여 변환을 해주어야 한다.

내장 연산자들

 Python은 (+, * 등등과 같은) 표준에서부터 bit shifting을 수행하는 연산자들, bitwise 논리 함수들  등과 같이 특수한 연산자들까지 다양한 내장 연산자들을 제공한다. Python에서 이들 연산자의 대부분은 다른 language들과 별반 다른 것이 없으므로 크게 다루지는 않을 것이다. Python 내장 연산자(built-in operators)는 documentation에서 전체 list를 찾을 수 있다.

Python 기본 style

 Python은 들여쓰기로 code block들을 정의하는 것 외에는 coding style에 있어서 제약사항이 적은 편이다. 들여쓰기 style도 깊이나 type(tab이나 space)을 가리지는 않는다. 하지만 Python Enhancement Proposal (PEP) 8(http://www.python.org/dev/peps/pep-0008)에 포함된 우선시  되는 문체 규약이 존재한다. 다음 표는 발췌된 Python 규약을 보여주고 있지만, Python의 style에 익숙해지기 위해서는 주기적으로 PEP 8을 읽는 것이 좋다.

표 Python coding 규약

상황
제안
예제
module/package 이름
짧게, 모두 소문자로, 필요하다면 underline(_) 사용.
imp, sys
함수 이름
모두 소문자로, 가독성을 위해 underline(_) 사용
foo(), my_func()
변수 이름
모두 소문자로, 가독성을 위해 underline(_) 사용
my_var
Class 이름
단어마다 대문자로 시작
MyClass
상수 이름
모두 대문자로 작성하고 underline(_)으로 단어를 구별한다.
PI, TAX_RATE
들여쓰기
level 별로 tab 사용하지 않고 4칸의 space 사용
비교
명확하게 True False 비교하지 않는다.
if my_var:
if not my_var:


 PEP 8의 규약을 따르는 것을 강력하게 권장한다. 이는 신중하게 선택되고 시간을 들여 test된 결과로 규약에 맞게 작성된 code는 가독성이 좋을 뿐더러 다른 이들도 이해하기 쉽게 만들어 준다.

정리

 여기에서 Python에 대해 살짝 살펴보았다. 당신이 programming 경험이 있다면 Python으로 code를 어떻게 작성할지 감이 올 것이다. 이 경우에 당신의 code를 실험하는데 편안함을 가질 수 있다. 많은 programmer들은 다양한 language들을 경험했으므로 Python 문법을 놀랄만큼 쉽게 익힐 수 있다는 것을 경험했다. 일단 language의 기본을 익히기만 하면 익숙해지고 단순해지는 것은 금방이다. 여기에서 설명한 기초사항에 대해서 잘 숙지하기 바란다.