[Python101] 005 함수,모듈, 그리고 도움이 되는 도구들

지난 시간까지 기본적인 프로그래밍에 필요한 “입출력”을 다루는 부분을 간단하게 나마 살펴보았다. 실제로 지금까지의 내용은 뭔가 설명이 필요하거나 개념적인 이해를 도모하는 부분과는 조금 거리가 있었고, 마치 조리법처럼 “이렇게 하면 이렇게 이렇게 됩니다.” 정도였기에 경우에 따라서는 조금 재미도 떨어지고 지겨운 부분이 없지 않아 있었을 것으로 생각된다.

이번 시간부터는 프로그램을 구성하는 단위와 이를 어떻게 만드는지, 그리고 프로그램의 흐름은 어떤 식으로 만들어지는지를 살펴보고자 한다.

모듈

모듈(Module)이라는 것은 다른 것으로 대체 가능한 어떤 구성 요소를 뜻하는데, 파이썬에서는 미리 만들어두었다가 필요할 때 꺼내 쓰는 레고 조각같은 프로그램의 조각을 말한다. 보통 프로그램의 소스 코드가 몇 백줄에서 몇 천줄까지 커지는 크고 복잡한 프로그램을 만든다면 이를 하나의 파일에 모두 작성하게 되면 사소한 오타로 인해 발생하는 에러를 잡기도 힘들어지고, 나중에 어떤 부분을 수정해야할 때 큰 범위를 일일이 찾아야 하므로 상당히 불편하고 어려워진다. 파이썬 프로그램 소스는 그 단위 단위가 모두 ‘모듈’이고, (뒤에서 설명할) 단위 프로그램 내의 함수나 클래스 같은 것들도 한 편으로는 모듈이라고 할 수 있다.

예를 들어 운영 체제에서 어떤 파일이나 폴더가 있는지를 검사하고, 파일을 복사, 삭제하거나, 폴더에 파일이 몇 개나 들어있는지를 알아내는 함수들을 만들었다고 하자. 나중에 이런 기능을 다른 프로그램에서도 사용해야 한다면, 그 때가서 똑같은 기능을 일일이 구현하는 것은 상당히 번거로운 일이 될 수도 있다.

그래서 이런 여러 개의 함수를 path(경로)라는 모듈로 묶어준다. 그리고 이런 경로와 관련된 것외에 운영체제의 특성이나 명령과 관련되는 모듈들을 다시 묶어서 os라는 모듈로 만들어둘 수 있겠다. 그리고 이게 파이썬이 기본적으로 제공하는 os 라이브러리의 정체가 된다.


from os.path import exists

라는 구문을 통해서 파일의 존재여부를 알아낼 수 있는 exists()라는 함수를 이미 사용해 본 바가 있다. (이는 우리가 구현한 것이 아니라 이미 구현되어 있는 함수를 가져다 사용한 예이다.)

파이썬을 설치하면 기본적으로 함께 설치되는 표준 라이브러리에도 활용가치가 높은 모듈들이 많이 있으며, 또 이미 많은 개발자들이 유용한 모듈들을 만들어서 공개해두고 있어 엄청나게 많은 활용 가능한 모듈들이 있다. 그래서 파이썬으로 작은 유틸리티를 만드는 일은 무척이나 쉬울 수 있다. (거의 필요한 기능들은 찾아보면 다 만들어져 있어서) 마치 레고로 자동차를 조립하는 것처럼 핸들, 바퀴, 차대 등의 부속품을 import 하여 필요한 모듈들이 함께 동작하도록 만들어주면 되는 것이다.

import / from… import

지금 편집하고 있는 소스코드 파일이 아닌 다른 곳에서 모듈을 가져와서 사용할 때 import 명령을 사용한다. import 명령은 다른 모듈 파일의 전체 혹은 일부를 현재 프로그램으로 반입해 오는 명령이다. 반입한 객체는 마치 미리 정의한 것과 같은 효과를 갖게 된다. 덕분에 프로그램 소스 코드가 간결해지고, 만들어야 하는 코드가 적어진다. (게다가 이렇게 모듈로 만들어둔 프로그램은 다른 프로그램에서 쉽게 재사용할 수 있게 된다.)

또한 모듈로 작성된 파일 내에서 그 일부만 반입해오는 경우에는 from 모듈이름 import 실제 반입할 모듈과 같은 식으로 코드를 반입할 수 있다.

모듈을 통째로 반입한 경우에는 그 하위에 있는 함수를 사용할 때 모듈.함수()와 같은 식으로 . 구분자를 써서 이들을 연결해 줘야 하지만 from 모듈 import 함수한 경우에는 함수 이름을 그대로 사용해주면 된다.

실제로 모듈을 만들어서 사용하는 예는 이 글의 말미에서 다시 다루기로 하고, 이번에는 함수에 대해 알아보도록 하겠다.

함수

함수는 프로그래밍에서 가장 중요한 개념 중의 하나이다. 함수는 “가장 작은 온전한 프로그램의 최소 단위”이다. 이 말이 무슨 뜻인고 하니, 우리가 흔히 ‘함수’라고 하면 y=2x+5와 같이 중고등학교 수학시간에 배운 함수를 떠올리게 된다. 음… 맞다. 함수는 딱 저렇게 생겨서 동작하게 된다. 여전히 감이 잘 오지 않는데, 이 함수를 잘 살펴보도록 하자.

x = 1 을 넣으면 y = 7이 된다.` x = 2` 를 넣으면 y = 9가 된다. 즉 어떤 값을 입력 (x에 대입)해 주면 이 값을 처리하여 그 결과값을 돌려주고 있다. 그리고 그 결과는 “입력된 값을 2배하고, 거기에 5를 더한다”는 처리를 한 결과값이다.

프로그래밍에서의 함수는 “가장 작은 프로그램의 단위”라고 했다. 프로그램 자체가 입력을 받아 이를 처리하고 그 결과를 출력해주는 기계 장치이므로, 이러한 프로그램의 특성을 함수는 그대로 가지고 있다. 그래서 프로그램 그 자체도 함수이며, 프로그램은 작고, 많은 함수들이 결합된 형태로 만들어진다.

그럼 어떤 기능을 함수로 만들면 좋을까? 답은 “반복적으로 하게 되는 작업”을 함수로 만들면 된다. 그 역시 감이 잘 오지 않는다면 “함수는 타이핑을 줄여주는 테크닉“이라고 처음에 생각해도 크게 무리가 없다.

함수 만들기

실제로 함수를 한 번 만들어 보자. 함수를 만드는 키워드는 def 이다. 함수는 다음과 같이 생성한다.

def 함수이름(인자값, ...):
    # << 어떤 동작을 하는 코드들 >>
    return 반환값 

def 키워드 다음에 함수의 이름을 쓴다. 그런 다음 함수가 받는 인자값의 이름을 써준다. 문장의 끝은 콜론으로 끝나고, 실제 함수가 해야 하는 동작은 모두 들여쓰기 해준다. 위에서 이야기한 y = 2x + 5를 파이썬 함수로 만들어보자.

def doublePlusFive(x):
    y = 2*x + 5
    return 5

print(doublePlusFive(1)) #==> 7
print(doublePlusFive(2)) #==> 9
print(doublePlusFive(5)) #==> 15

물론 위의 예제에서는 함수를 만드는 예를 보이다보니 저럴 거면 왜 함수를 쓰느냐고 할 수 있는데, 만약 섭씨나 화씨 온도를 서로 변환해야 하는 경우를 생각해보자. 섭씨온도를 화씨 온도로 바꾸는 식은 다음과 같다.

℉ = ℃ * 9 / 5 + 32

반대로 화씨 온도를 섭씨온도로 바꾸는 식은 다음과 같다. (위의 식을 바꾼 것에 지나지 않는다.)

℃ = (℉ - 32) * 5 / 9

그럼 화씨와 섭씨를 각각 바꿔주는 함수는 다음과 같이 작성할 수 있을 것이다.

#ex12.py
def FtoC(fh):
    return (fh-32) * 5 / 9.0

    def CtoF(cd):
        return cd*9/5.0 + 32

이렇게 함수로 만들어두면 나중에는 FtoC(45) 라고만 쓰면 화씨 45도가 섭씨 몇 도에 해당하는지 쉽게 알 수 있게된다. 만약 코드상으로 저 공식을 바로 사용하는 것도 “똑같은” 방법이라 할 수 있겠지만 1) 시간이 지나고 나서는 이 공식이 뭔지 기억이 안날 수도 있고, 2) 나중에 다시 같은 공식을 써야할 때 공식이 생각나지 않는 경우가 생길 수 있다.

대신에 함수를 사용하면 1)함수의 이름으로 이게 무슨 처리를 하는지 유추할 수 있고1 2) 함수를 모듈로 만들어 놓으면 굳이 공식을 기억하지 않아도 함수를 바로 사용할 수 있다.

함수와 모듈

위의 소스 코드를 ex12.py로 저장하고 이를 모듈로 사용하는 ex13.py를 새로 작성해보도록하자.

#ex13.py
#이 파일은 ex12.py와 같은 폴더에 저장해야 함.

import ex12

celsius = 25
farenheit = 45

print("섭씨 %d도는 화씨로 %f입니다." % (celsius, ex12.CtoF(celsius))
        print("화씨 %d도는 섭씨로 %f입니다." % (farenheit, ex12.FtoC(farenheit))

ex13.py는 ex12.py의 내용을 ex12라는 이름의 모듈로 입수한다. 우리가 이미 작성한 ex12.py 파일내의 모든 내용이 이 부분에 덧붙는 다고 생각하면 된다.

또한 우리가 반입한 내용이 ex12 전체이기 때문에 그 속에 들어있는 함수를 사용할 때는 ex12.FtoC(), ex12.CtoF()와 같은 식으로 반입한 모듈의 이름을 앞에 붙여주고 점(.)으로 구분해 준다. 만약 FtoC(), CtoF()의 이름을 그대로 사용하고 싶다면 다음과 같이 import 구문을 바꿔주면 된다.

from ex12 import FtoC
from ex12 import CtoF

모듈의 위치

모듈로 반입해 올 수 있는 파일의 위치는 특정한 범위로 제한된다. 현재 실행되는 프로그램 소스와 같은 폴더에 있거나, 파이썬의 표준 모듈 폴더에 있어야 한다. 이 표준 모듈 폴더는 sys.path라는 곳에 저장되어 있는데 여기에 특정한 폴더를 추가해 줄 수도 있다. 이 방법에 대해서는 나중에 다시 살펴볼 기회가 있을 것이다.

대화형 쉘 활용하기

지금까지 대화형 쉘은 그저 “계산기” 정도의 용도로 쓴 것이 사실이다. 단순히 하나의 명령이 어떤 일을 하는지 이미 알고 있는 상황에서 print 명령을 쓴다거나 하는 일이 그리 ‘효율적’으로 느껴질리도 없다. 지금부터는 대화형 쉘을 어떻게 활용할 수 있는지 살펴보겠다.

함수를 테스트하기

대화형 쉘은 기본적으로 한 번에 한 줄의 명령을 실행할 수 있도록 만들어져 있다. 즉 명령문을 입력하고 엔터키를 누르면 해당 명령이 바로 실행되어 즉시 그 결과를 볼 수 있는 것이다.

하지만 함수를 만드는 def 구문을 쓸 때는 엔터를 누르더라도 바로 실행되지 않는다. 위에서 예를 들었던 doublePlusFive() 함수를 대화형 쉘 모드에서 입력해보라. def doublePlusFive(x): 하고 엔터를 누르면 프롬프트가 나오지 않고 들여쓰기 상태가 된다. 이 상태에서 함수의 나머지 코드를 입력하고, 엔터를 두 번 누르면 결과가 출력되지 않고 다시 프롬프트가 표시된다.


>>> def doublePlusFive(x):
y = 2*x+5
return y

>>> doublePlusFive(7)
19

다시 프롬프트에서 doublePlusFive(7)을 입력하고 엔터를 치면 해당 함수가 실행되어 계산 결과를 표시하게 된다. 즉 대화형 쉘은 메모리에 만들어진 수식이나 읽어들인 외부 모듈을 계속 가지고 있으므로 간단한 ‘테스트’를 해보는 데 큰 도움이 된다. 특히 앞으로 배우게 될 리스트와 관련하여 애매한 부분들은 대화형 쉘에서 간단히 시험해봄으로써 정확한 명령문을 결정하는 데 도움이 될 수 있다.

모듈 함수의 도움말을 보기

help() 명령은 특정한 모듈 혹은 함수의 도움말을 표시해주는 명령이다. 백문이 불여일견, help(max)라고 대화형 쉘에서 실행해보자. max()는 이름에서 유추할 수 있지만 최대 값을 구하는 함수이다. 이 함수의 help 결과는 다음과 같다.


>>> help(max)
Help on built-in function max in module __builtin__:

max(...)
max(iterable[, key=func]) -> value
max(a, b, c, ...[, key=func]) -> value

With a single iterable argument, return its largest item.
With two or more arguments, return the largest argument.

help에서 표시하는 정보는 max__builtins__ 라는 특별한 이름의 모듈에 속해 있는 함수임을 알 수 있고, max(a, b, c, d...) 이런 식으로 쓰면 그 중에서 가장 큰 값을 반환한다는 설명을 볼 수 있다.

그러면 한 번 테스트해보자.


>>> someNumbers = (1,2,3,4,5)
>>> max(someNumbers)
    5

someNumber라는 변수에 (1,2,3,4,5) 라는 숫자 묶음을 대입해주고, max를 통해 someNumber 중에서 가장 큰 숫자를 구하는 명령을 실행해보면 최대 값을 구해 반환하는 것을 볼 수 있다.

모듈이 어떤 기능을 수행할 수 있는지를 살펴보는 방법

우리는 방금 ‘최대값’을 구하는 함수를 어떻게 사용하는지 살펴보았다. 그렇다면, 반대로 최대값을 구하는 함수도 있지 않을까? 이름으로 유추해보자면 min()이라는 함수가 있을 것 같다. 그럼 그런 함수가 있는지 없는 지 어떻게 알 수 있을까?

이럴 때 유용하게 사용할 수 있는 함수가 있다. 바로 dir()이라는 내장 함수이다. 이 함수는 인자로 받은 모듈에 포함되어 있는 하위 기능을 모두 열거해준다.

우리는 조금전 help(max)에서 이 기능이 “builtins“라는 특별한 모듈에 속해있다고 하는 것을 보았다. 양끝에 언더바(_)가 두 개씩 붙은 것은 “내부적으로”라는 의미라고 이해하면 되고 실제 글자로는 built-in된 모듈이라는 의미이다. dir 함수는 모듈의 내부 구성 요소를 볼 수 있는 명령이라 하였으니 이 builtins 모듈의 내부에 정말 min 이라는 함수가 있는지 살펴보도록 하자.


>>> dir(__builtins__)
['ArithmeticError', 'AssertionError', 'AttributeError',
'BaseException', 'BufferError', 'BytesWarning',
'DeprecationWarning', 'EOFError', 'Ellipsis',
'EnvironmentError', 'Exception', 'False', 'FloatingPointError',
'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError',
'ImportWarning', 'IndentationError', 'IndexError', 'KeyError',
'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError',
'None', 'NotImplemented', 'NotImplementedError', 'OSError',
'OverflowError', 'PendingDeprecationWarning', 'ReferenceError',
'RuntimeError', 'RuntimeWarning', 'StandardError', 'StopIteration',
'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit',
'TabError', 'True', 'TypeError', 'UnboundLocalError',
'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError',
'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning',
'ValueError', 'Warning', 'WindowsError', 'ZeroDivisionError',
'_', '__debug__', '__doc__', '__import__', '__name__',
'__package__', 'abs', 'all', 'any', 'apply', 'basestring',
'bin', 'bool', 'buffer', 'bytearray', 'bytes', 'callable',
'chr', 'classmethod', 'cmp', 'coerce', 'compile', 'complex',
'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod',
'enumerate', 'eval', 'execfile', 'exit', 'file', 'filter',
'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr',
'hash', 'help', 'hex', 'id', 'input', 'int', 'intern',
'isinstance', 'issubclass', 'iter', 'len', 'license',
'list', 'locals', 'long', 'map', 'max', 'memoryview', 'min',
'next', 'object', 'oct', 'open', 'ord', 'pow', 'print',
'property', 'quit', 'range', 'raw_input', 'reduce',
'reload', 'repr', 'reversed', 'round', 'set', 'setattr',
'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super',
'tuple', 'type', 'unichr', 'unicode', 'vars', 'xrange', 'zip']

여기서 표시되는 이름들은 거의 모두가 내장 함수 혹은 내장 모듈들이다. 앞쪽에 대문자로 시작하는 것들은 거의 내장 모듈이나 상수들을 의미하며, 중간에 __로 둘러 싸여진 이름은 모듈 내에서 다시 “내부적으로” 사용되는 기능이다. 마지막에 abs… 부터가 실제 우리가 자주 사용하는 내장 함수 들의 이름이다.

이러한 내장 함수의 이름이나 사용법을 절대로 다 외울 필요가 없다. 앞으로 공부를 해 나가면서 필요한 함수들은 그만큼 자주 사용하게 될 것이니 자연스럽게 익히게 될 것이다. 대신, 뭔가 새로운 모듈이나 함수를 앞으로 접하게 된다면 dir 및 help 명령을 통해 사용법을 확인하고 다른 연관된 명령이 있는지 살펴보는 것은 큰 도움이 된다. 반드시 이런 식으로 공부를 해 나갈 것을 권한다.

1 그래서 함수의 이름을 잘 정하는 것은 엄청나게 중요한 일이다.

[Python101] 004. 파일. 파일을 읽고, 파일에 쓰기

사용자로부터 입력을 받아 데이터를 처리하는 프로그램은 실질적으로 효율에 한계가 있다. 처리해야 하는 데이터를 사용자가 일일이 매번 입력해야 하기 때문이다. 컴퓨터는 귀찮고 반복적으로 처리하는 작업을 수월하게 하라고 있는 것이므로 프로그램은 가능한한 많은 과정을 자동화하는 방향으로 처리하는 것이 좋은 경우가 많다.

보통의 경우에는 다음과 같은 방식의 순서로  작업을 많이 처리하게 된다.

  1. 처리해야 할 데이터를 미리 준비 (텍스트 파일이나 엑셀 파일 등)
  2. 프로그램을 실행할 때 매개변수로 처리할 파일을 주고 실행한다.
  3. 프로그램이 데이터 파일을 읽어 들여서 데이터를 주르르르륵 처리한다.
  4. 처리한 결과는 또 다른 파일에 기록되거나 화면에 출력된다.

이것은 일종의 자동화 작업이고, 파이썬은 이런 작업에 대한 처리를 쉽고 빠르게 처리하기에 매우 좋다.

파일 읽기

데이터를 저장한 파일로부터 데이터를 읽는 방법에 대해 먼저 살펴보도록 하자. 예를 들어 메모장으로 작성한 텍스트 파일의 내용을 읽어들이고, 뭔가 내용을 쓰는 작업은 다음과 같은 절차를 거친다.

  1. 파일을 연다. 파일을 열게 되면 파이썬은 이 파일을 다루기 위한 핸들러(Handler)를 사용하게 된다.
  2. 파일의 내용을 읽어들인다. 파일의 내용을 읽어들이는 작업은 파일을 열면서 생성한 핸들러가 중계해준다. 핸들러는 파이썬 스크립트와 실제 데이터 파일 사이를 중계해주는 모듈이라 생각하면 된다.
  3. 파일에는 새로운 내용을 쓰거나, 기존 파일의 내용 뒤에 내용을 추가하는 것도 가능하다. 이 역시 핸들러에 의해 데이터를 쓸 수 있다.
  4. 파일 다 사용했으면 파일을 닫는다. 만약 파일을 적절히 닫지 않으면 파이썬 프로세스가 정상적으로 종료되지 못하거나, 다른 프로그램이 해당 파일을 쓰지 못하는 경우가 발생할 수 있다.

파일을 열기 위해서는 open 명령을 사용한다. open 명령은 다음과 같이 사용한다.

파일핸들러 = open('파일의 경로', [모드])

open  명령을 사용해서 파일을 열면 파일의 핸들러를 얻을 수 있다. 이 핸들러를 통해 파일의 내용을 읽어들이거나, 파일에 데이터를 쓰는 작업이 가능해진다.

ex09.py

아홉번째 예제는 텍스트 파일을 열어서 그 내용을 보는 예제이다.이 예제를 제대로 실행하기 위해서는 텍스트 파일 하나가 필요하다. 메모장을 열어 아무 텍스트나 몇 줄 입력한 후에 예제를 저장하는 폴더에 저장한다. 이름은 구분하기 쉽게 ex09.txt로 하겠다.

April

Still an irritating wind;
Vestiges of stubborn grey –
Jibing us of recent winter blight.

It’s coming though – like perky breasts
Pushing through a blouse –
Teasing, pleasing in it’s tantalising play:

Warmth of youth in April sun –
Simmering off depression,
Brains retuned; remapped for fun.

April is a portal –
Smoothly transitions
Delicate dispositions – suchlike mine,

Easing hunched bodies into
Summery smiles.

이제 ex09.py 의 소스 코드는 다음과 같다.

from sys import argv

script, filename = argv

txt = open(filename)

    print "Here's your file %r:" % filename
print txt.read()

    print "Type the filename again:"
    file_again = raw_input('> ')

txt_again = open(file_again)
    print txt_again.read()

argv 가 등장하는 것을 보니, 파라미터를 받고 실행하는 프로그램이다. 실행은 앞의 강좌에서 소개했던 것과 같은 방식으로 하면 된다.

 > python ex09.py ex09.txt 이렇게 실행한 결과는 다음과 같다.

Here's your file 'ex09.txt':
April

Still an irritating wind;
Vestiges of stubborn grey
Jibing us of recent winter blight.

It’s coming though  like perky breasts
Pushing through a blouse
Teasing, pleasing in it’s tantalising play:

Warmth of youth in April sun
Simmering off depression,
Brains retuned; remapped for fun.

April is a portal
Smoothly transitions
Delicate dispositions ? suchlike mine,

Easing hunched bodies into
Summery smiles.
Type the filename again:
> ex09.py
from sys import argv

script, filename = argv

txt = open(filename)

print "Here's your file %r:" % filename
print txt.read()

print "Type the filename again:"
file_again = raw_input('> ')

txt_again = open(file_again)
print txt_again.read()

자 이제 코드를 좀 살펴보자.

1) 3행을 보면 파일 이름을 argv로부터 읽어온다.

2) 5행에서는 이 파일 이름을 사용하여 해당 파일을 연다. 파일 이름만 전달 받았으므로 파이썬 코드 파일과 같은 폴더 내의 파일을 탐색하게 된다. 그리고 파일을 열어서 그 핸들러는 txt라는 이름의 변수에 대입된다.

3) txt는 곧 파일 핸들러라고 했다. 파일 핸들러는 여러 기능 모듈을 가지고 있는데 그 중 하나가 read() 이다. 이 모듈은 파일의 내용을 전부 읽어들이는 일을 한다.

이 때 txt 모듈의 read() 를 실행하기 위해서는 구두점(.)으로 이를 연결해준다. 즉 txt.read() 는 txt 모듈의 read라는 기능 모듈을 실행한다는 뜻이다. 실행이 가능한 모듈은 주로 ()가 뒤에 붙는데, 이렇게 실행이되는 모듈을 특별히 ‘함수’ 혹은 ‘메소드’라고 한다.

txt.read() 모듈은 파일 전체의 내용을 읽어 이를 돌려준다. 8행은 이 결과를 모두 출력하게 된다.

4) 10행에서는 다른 파일 이름을 다시 물어본다. 나는 ex09.py를 입력했다. 파이썬 스크립트 소스 자체도 텍스트 파일이다. 단지 관습적으로 .py 라는 확장자를 썼을 뿐이다.

5) 주목할 것은 마지막의 14행이다. txt_again은 파일을 열고 그 핸들러를 대입하게 된다. 즉 txt_again이 파일의 핸들러이고, open() 이 실행된 결과와 동일하다. 즉 open()의 결과가 파일 핸들러라는 이야기다. 따라서 13, 14행은 다음의 한 행으로 합칠 수 있다.

print open(file_again).read()

파일에 쓰기

ex09.py는 파이썬에서 다른 텍스트 파일의 내용을 읽어와서 사용할 수 있음을 보여주었다. 주소록 정리라든지, 성적 계산, 혹은 이름-이메일 정보를 가진 주소록을 가져와서 받는 사람 주소에 맞게 사람 이름이 들어가는 이메일을 보내는 프로그램 등을 만들 수 있을 것이다.

이번에는 내용을 파일에 기록하는 작업에 대해 살펴보자. 지금까지는 open() 명령에서 모드를 따로 지정하지 않았다. 모드를 따로 지정하지 않은 open()은 기본적으로 “텍스트 파일”을 “읽기”모드로 열게 된다. 파일을 기록하기 위해서는 파일을 w 모드로 열면 된다. w 모드로 파일을 여는 것은 사실 새로운 파일을 만들고 그곳에 내용을 기록하는 것을 의미한다. 따라서 파일 이름이 기존에 있던 내용이면, 그 파일을 덮어쓰게(overwrite) 된다는 점을 참고하자.

ex10.py는 사용자로부터 3줄의 텍스트를 입력받아 이를 파일에 기록해주는 프로그램이다.

from sys import argv

script, filename = argv

print "We're going to erase %r." % filename
print "If you don't want that,hit Ctrl-C(^C)."
print "If you do want that, hit RETURN."

raw_input('?')

print "Opening the file..."
target = open(filename, 'w')

    print "Truncating the file. Goodbye!"
target.truncate()

    print "Now I'm going to ask you for three lines."

    line1 = raw_input("Line 1:")
    line2 = raw_input("Line 2:")
    line3 = raw_input("Line 3:")

    print "I'm going to write these to the file."

target.write(line1)
    target.write('\n')
target.write(line2)
    target.write('\n')
target.write(line3)
    target.write('\n')

target.close()

코드를 보면 알겠지만, 텍스트 파일의 이름을 파라미터로 받고 있다. 따라서 콘솔에서 파일을 실행할 때 텍스트 파일의 이름을 준다. 이 코드에는 파일의 내용을 지우는 truncate() 명령이 포함되어 있는데, 위에서 작성했던 ex09.txt 파일을 변경하도록 해보자. 결과는 아래와 같고, 하이라이트 된 라인은 실제 프롬프트에서 명령을 입력한 라인이다.

c:\Apps\textfiles>c:\Python27\python ex10.py ex09.txt
We're going to erase 'ex09.txt'.
If you don't want that,hit Ctrl-C(^C).
If you do want that, hit RETURN.
?
Opening the file...
Truncating the file. Goodbye!
Now I'm going to ask you for three lines.
Line 1:ABCDEFGHIJKLMNOPQRSTUVWXYZ
Line 2:abcdefghijklmnopqrstuvwxyz
Line 3:0123456789
I'm going to write these to the file.

c:\Apps\textfiles>type ex09.txt
ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
0123456789

텍스트 파일의 이름을 파라미터로 주고 프로그램을 실행하면 먼저 기존 파일의 삭제 여부를 묻게 된다. 엔터를 누르면 계속 진행을 하게 되고 파일을 지운다. 그런 다음 세 줄의 텍스트를 입력 받고, 이를 파일에 기록하게 된다.type 명령 (터미널에서는 cat 명령)으로 파일의 내용을 살펴보면 입력한 내용으로 해당 파일의 내용이 바뀌어 있음을 볼 수 있다.

코드의 내용을 분석해보도록 하자.

1) 파일의 이름을 filename 이라는 변수에 대입해준다. 이 파일 이름은 파라미터로 전달받은 값이다.

2) 5~7 행에서는 파일의 이름을 표시하고, 취소할 기회를 준다. 이때 ^C (ctrl+c)를 누르면 프로그램의 실행이 취소되고, 엔터를 누르면 다음으로 진행하게 된다.

3) 11~15행에서 해당 파일을 “쓰기 모드”로 열고 내용을 모두 지운다. 파일핸들러의 truncate() 명령은 내용을 모두 지우는 기능을 수행한다. 사실 “w”를 사용해 쓰기 모드로 파일을 열고 다른 내용을 기록하면 이전의 내용은 모두 지워지게 된다. 따라서 15행은 실질적으로는 필요 없는 셈이다. (15행을 주석 처리하고 한 번 실행해보라.)

4) 17~21행에서 다시 각 라인을 입력 받아 line1, line2, line3에 각각 입력 받은 내용을 추가한다.

5) 25~30 행에서는 파일 핸들러 targetwrite() 기능을 이용해서 각각의 문자열을 파일에 쓴다. 이 때 각 line1, line2, line3 은 줄바꿈 문자를 포함하고 있지 않으므로 이를 추가해 준다. 물론 이는 target.write(line1+"\n") 과 같이 써서 줄바꿈 문자를 더한 문자열을 파일에 써도 된다.

6) 끝으로 파일을 닫는다.

물론 하나의 프로그램에서 파일을 2개 이상 동시에 여는 것도 가능하다. 각각의 열린 파일은 핸들러로 조작할 수 있으므로 2개의 핸들러를 open 명령으로 만들어주면 된다.

파일 복사 프로그램

이 글의 서두에서 언급한 파일 복사하는 프로그램을 작성해 보겠다. 사실은 무척이나 단순하다. 이 프로그램은 1) 파라미터로 원본 파일과 복사할 위치를 입력받는다. 2) 원본 파일의 길이(몇 바이트나 되는지)를 알려주고, 3)복사할 위치에 이미 파일이 존재하는지를 알려준다. 그런 다음 4) 원본 파일의 내용을 읽어와서 사본 파일에 쓴다. 5) 두 파일을 닫는다.

ex11.py

이상의 내용을 코딩한 ex11.py의 내용은 다음과 같다.

#-*-coding:utf-8
from sys import argv
from os.path import exists

script, from_file, to_file = argv

print "Copying from %s to %s" % (from_file, to_file)

    input = open(from_file)
indata = input.read()
    print "The input file is %d bytes long." % len(indata)

    print "Does the output file exists? %r" % exists(to_file)
    print "Reday, hit RETURN to continue, CTRL-C to abort."
raw_input()

    output = open(to_file, 'w')
output.write(indata)

    print "Alright, all done."

    output.close()
input.close()

실행 결과는 다음과 같다. 이미 만들어져있는 그리고 만만한 ex09.txt를 다른 파일로 복사해보도록 하겠다.

c:\Apps\textfiles>c:\Python27\python.exe ex11.py ex09.txt ex09.bak
Copying from ex09.txt to ex09.bak
The input file is 65 bytes long.
Does the output file exists? False
Reday, hit RETURN to continue, CTRL-C to abort.

Alright, all done.

c:\Apps\textfiles>type ex09.bak
ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
0123456789

코드 내용 분석을 보자. 무척이나 단순하고 간단한데, 못 보던 기능을 발견했다. 바로 os.pathexists 라는 명령이다.

1) os.path 로부터 exists라는 함수를 반입해온다. os 는 파이썬 프로그램이 실행되는 컴퓨터의 운영체제와 관련된 모듈들의 집합이다. 그리고 그 중에는 path라는 모듈이 있는데, 이 모듈은 디스크 내의 경로, 파일 등과 관련된 기능들이 모여있다. exists 모듈은 path에 들어있는 하위 객체인데, 주어진 경로에 파일이 이미 존재하는지를 검사하여 존재한다면 True를 돌려주는 기능을 한다.

2) input 은 원본 파일을 열어서 그 핸들러를 얻는다. input의 read() 명령을 통해 파일의 전체 내용을 읽어 indata에 대입한다.

3) 13~15는 파일의 길이를 알려주고, 복사본 위치를 찾아 거기에 이미 파일이 있는지를 알려준다. 엔터를 입력하면 raw_input() 뒤의 코드가 계속 실행된다.

4) 'w' 모드로 복사본 파일을 연다. 그런 다음, indata를 쓴다.

5) 끝으로 두 파일을 닫으면 된다.

위의 실행 결과에서 알수 있듯이, 파라미터로 준 파일을 보면 내용이 복사되어 있음을 알 수 있다.

사실 파일 입출력은 쉬운 내용은 아니다. ‘핸들러’라는 눈에 보이지도 않는 추상적인 개념을 도구로 다루기 때문이다. 하지만 이런 추상적인 개념은 사실 이해하기보다는 익숙해지면 쉽게 느끼게 된다. (우리가 흔히 하는 덧셈, 뺄셈도 분명 그 원리는 우리가 알고 있지만 엄밀하게는 익숙하게 느끼기 때문에 쉽게 생각할 수 있는 것이다.)

파일 입출력에 대해 간단히 알아보았다. 이로써 기본적인 입력과 출력을 처리할 수 있는 방법에 대해서는 기본기를 파악했으니, 다음 시간부터 실제 프로그램을 움직이는 흐름인 로직에 대해 살펴보기로 하겠다.

[Python101] 003. 입력. 사용자로부터 입력받기

지난 시간까지 계산 결과를 적절하게 출력하는 방법에 대해 살펴보았다. 어떤 처리 결과를 출력하는 방법을 보았으니, 이번에는 처리하기 위한 데이터를 입력 받는 방법을 살펴보겠다.

사용자 입력에는 여러 가지가 있다. 키보드로 입력을 받는 경우도 있고, 마우스로 클릭하거나 드래그하여 그림을 입력받는 경우도 있다. 이는 모두 사용자에 의한 직접적인 입력이다. 또 이런 식으로 사용자가 직접 입력을 하는 경우 말고 미리 작성된 파일로 부터 데이터를 읽어와서 처리하거나 인터넷 등 네트워크로부터 데이터를 전송받아 처리하는 경우들도 있다.

이러한 입력 방법 중에서 가장 쉽게 접근할 수 있는 키보드를 통한 입력에 대해 먼저 알아보도록 하자. 마우스를 통한 입력은 “창”이 있는 프로그램에서 쓰이는 방법인데, 아쉽게도 파이썬은 이런 프로그램을 만들 수는 있지만 상당히 많은 양의 코딩이 필요하다. (실제로 IDLE은 순수 파이썬으로 만들어진 편집기이다.) 이 부분은 나중에 기회가 되면 다루기로 하고 먼저 키보드를 통한 사용자 입력을 받아 처리하는 방법을 살펴보자.

키보드를 통한 사용자입력

키보드를 통한 사용자 입력 역시 엄밀히 이야기하면 2종류로 나뉠 수 있다. 하나는 파라미터로 입력을 받는 방법과 다른 하나는 프롬프트를 통해 입력을 받는 방법이다. 용어가 좀 어려운데 파라미터로 입력을 받는 방법은 옛날 도스 시절에 복사 명령을 보면 된다.

copy C:\원본.txt D:\backup\사본.txt

위의 명령은 원본.txt 파일을 D드라이브에 있는 backup 폴더에 사본.txt로 복사하는 명령이다. 이 명령은 다음과 같이 각각의 의미가 있는 요소로 분리될 수 있다.

{복사 프로그램} {파라미터1(원본위치)} {파라미터2(사본위치)}

이와 같이 프로그램을 실행할 때 프로그램 이름 다음에 공백으로 구분하여 붙여주는 단어들을 파라미터라고 한다. 파라미터로 주어진 문자열들은 프로그램에서 조금 특별한 방법으로 인식해서 처리할 수 있다. (우리는 나중에 이와 비슷한 파일 복사 프로그램을 작성해 볼 것이다.)

그리고 프롬프트로 입력을 받는 경우는 도스창(콘솔)이나 파이썬 쉘을 생각하면 된다. 파이썬 쉘은 실행되면 >>> 라고 프롬프트를 표시하고 사용자의 입력을 기다린다. 사용자는 실행하고자 하는 명령을 입력하고 엔터를 누르면 해당 명령을 실행해 결과를 보여준다.

파이썬에서 사용자의 입력을 이렇게 받도록 해주는 명령은 raw_input() 이라는 모듈이다. 이 모듈은 사용자가 “엔터”키를 누를 때가지 실행을 중지하고 키보드를 통해 입력을 받는다. 입력이 완료되면 사용자가 입력한 문자열을 돌려주게 된다. 따라서 이는 다음과 같은 형식으로 사용한다.

something_user_enter = raw_input("표시할 질문")

그럼 ex06.py를 작성하면서 어떻게 쓰이는지 살펴보도록 하겠다.

#-*-coding:utf-8-*-
age = raw_input( "How old are you?")
height = raw_input( "How tall are you?")
weight = raw_input( "How much do you weight?")

print "So, you're %r old, %r tall and %r heavy." % (age, height, weight)

코드를 타이핑한 후 실행하면 How old are you? 가 나오고 더 이상 출력되지 않는다. 적절한 값을 입력하고 엔터를 누를 때마다 다음 질문이 나온다. 질문에 모두 답을하면 답변 받은 내용을 합성하여 보여주게 된다.

How old are you?19years
How tall are you?180cm
How much do you weight?100kg
So, you're '19years' old, '180cm' tall and '100kg' heavy.

이 예제에서는 포맷 문자열에서 치환자를 %r을 썼다. 실질적으로 이 명령을 통해 입력받은 값들은 모두 “문자열로 인식”된다. 만약 1이라고 답을 해주면 숫자 1이 아닌 글자 “1”이라는 글자를 받은 셈이 된다. 따라서 이 값들은 바로 덧셈, 뺄셈, 나눗셈 등의 수식 계산을 할 수 없다.

코드의 내용은 간단하다. 각각 질문을 표시해주고, 입력받은 내용을 변수에 대입해 둔 다음, 마지막에 한 문장에 합성하여 표시해주는 것이 끝이다. 특히 %r 치환자를 사용하면 문자열의 양 옆으로 따옴표가 생기는 점에 주목하자. 만약 키를 9′ 로 입력하면 어떻게 출력되는지도 관찰해 보라.

환경 변수로부터 파라미터 받기

위의 내용으로 다른 활용을 해보기 전에 이번에는 파라미터를 받는 법을 배워보자. 이전에는 보지 못했던 구문들이 나오는데, 일단 열심히 그리고 정확하게 타이핑해보라.

ex07.py

from sys import argv

script, first, second, third = argv

print "The script is called:", script
print "Your first variable is:", first
print "Your second vaiable is:", second
print "Your third vaiable is:", third

이를 IDLE에서 실행하면 실행이 되지 않고 오류가 난다.

Traceback (most recent call last):
  File "C:\Apps\textfiles\Learn Python the hard way\ex13.py", line 3, in <module>
    script, first, second, third = argv
ValueError: need more than 1 value to unpack

오류의 원인은 맨 마지막에 나오는데 unpack 할 값이 모자라다는 것이다. unpacking에 대해서는 조금 뒤에 설명할 것이니, 이제는 “콘솔에서 파이썬을 실행”해야 한다.

맥OSX 사용자는 ‘터미널’ 프로그램을 실행한다. 실행한 다음 파이썬 예제 파일을 저장해둔 폴더로 간다. 만약 문서 폴더 아래에 py 라는 폴더에 파일을 저장했다면 다음 명령으로 해당 폴더로 이동한다. ( $ 기호는 프롬프트이므로 입력하지 않는다.)

$ cd Document/pys

해당 파일(ex07.py)이 있는지 보기 위해서는 ls 명령을 실행해본다.

$ ls

파일이 있는 것이 확인되면 다음과 같이 실행해 준다.

$ python ex07.py 1 2 3

윈도 7 환경에서는 조금 명령이 다르다. 시작 메뉴 버튼을 눌러 cmd 를 입력하고 엔터한다. 우리가 흔히 도스창이라 부르는 콘솔이 나타난다. 만약 예제 파일을 저장한 위치가 c:\pys 라면 다음 명령을 입력하여 해당 폴더로 이동해야 한다. (마찬가지로 > 기호는 프롬프트 이므로 입력하지 않는다.) 특히, 윈도에서는 슬래시가 아닌 역슬래시이므로 주의하자. (콘솔에서는 원 표시로 표시될 것이다.)

> cd c:\py

파일이 있는지 보기 위해서는 dir 명령을 이용한다.

> dir

다음 python을 같은 방식으로 실행한다.

> python ex07.py 1 2 3

만약, 실행이 되지 않고 알 수 없는 명령이라고 하면 환경 변수에 파이썬 경로가 추가되지 않았다. 000번 강좌를 보고 path 를 수정해주어야 한다. 그렇지 않다면 다음과 같이 파이썬의 경로를 다 써줘도 상관없다.

> c:\python27\python ex07.py 1 2 3

다음과 같은 식으로 전체 실행 과정을 표시해 주겠다.

Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation. All rights reserved.

C:\Users\MYMYMYMY>cd c:\Apps\textfiles

c:\Apps\textfiles>dir
C 드라이브의 볼륨: OS
볼륨 일련 번호: 28B9-A7BB

c:\Apps\textfiles 디렉터리

2012-04-20  오후 04:14    <DIR>          .
2012-04-20  오후 04:14    <DIR>          ..
2012-04-19  오후 04:03                44 ex00.py
2012-04-20  오후 01:05               719 ex02.py
2012-04-20  오후 01:28               462 ex03.py
2012-04-20  오후 02:42               413 ex04.py
2012-04-20  오후 02:48               373 ex05.py
2012-04-20  오후 03:50               225 ex06.py
2012-04-20  오후 04:14               222 ex07.py
2012-04-19  오후 03:45    <DIR>          Learn Python the hard way
7개 파일               2,458 바이트
3개 디렉터리  172,006,219,776 바이트 남음

c:\Apps\textfiles>c:\Python27\python ex07.py 1 2 3
The script is called: ex07.py
Your first variable is: 1
Your second vaiable is: 2
Your third vaiable is: 3

c:\Apps\textfiles>

이제 신기하게도 명령 줄에서 입력한 문자가 프로그램 속으로 전달되어 표시되는 것을 볼 수 있다. (콘솔이나 터미널에서는 화살표 위쪽 방향키를 누르면 이전에 입력된 명령이 다시 표시되니, 쉽게 다른 글자로 바꿔 넣어보도록 하자.)

이제 원래 코드가 무슨 역할을 하는지 살펴보도록 하자

1) from sys import arvg : 이 문장은 sys 라는 모듈로부터 arvg 라는 모듈을 가져와서 사용할 수 있도록 한다는 의미이다. 대부분의 파이썬 프로그램은 모듈이라는 단위로 구성이 된다. sys라는 모듈에는 아주 많은 하위 모듈들이 있는데, 이 중에서 argv 라는 모듈을 가져와서 쓰겠다는 말이다.

sys 모듈은 파이썬이 실행되고 있는 환경에 대한 정보를 얻거나 변경할 수 있도록 해주는 모듈이다. 그리고  argv는 파라미터의 목록을 가져오는 모듈이다. 여기에 무슨 값이 들어가는지 생각해보자.

python ex07.py 1 2 3
------ ------- - - -
0      1       2 3 4

위는 방금 이 프로그램을 실행한 명령이다. 먼저 python은 파이썬 인터프리터를 실행하는 명령이다. 이 명령 뒤에 파라미터들이 붙어서 들어간다. 이들은 순서대로 ex07.py, 1, 2, 3 총 4개의 파라미터가 붙게 된다. (IDLE에서는 실행시에 python ex07.py 까지만 실행해준다.)

2) 3행은 argv에 들어있는 값을 쪼개서 4개의 변수에 순서대로 담아주게 된다. 즉 script, first, second, third 의 4개에 대해 argv에 들어있는 4개의 파라미터를 순서대로 담아준다.

순서대로 묶여있는 “데이터 묶음”을 이런 방식으로 대입해서 나누는 것을 unpacking 이라고 한다. 당장 unpacking을 외우거나 이해할 필요는 없다. 나중에 다시 보게 될 것이다. 이제 각 변수에 어떤 값이 들어가 있을 지 예상이 될 것이다. 나머지 부분은 각 파라미터로 들어온 변수를 개별적으로 출력해주는 부분이다.

효율적이지 못하다고 판단되는가? 그럴 수도 있다. 단순히 아이콘만 클릭해서 프로그램을 실행하는 것과는 무척이나 다르고 번거롭다. 하지만 이런 방식에 어느 정도 친해질 필요가 있다.

  • 디렉토리 이름을 일일이 타이핑하는 것은 무척 귀찮지만, 사실 tab 키를 사용하면 쉽게 입력할 수 있다. C:\py 까지만 입력하고 탭을 눌러보라. py로 시작하는 파일이나 폴더 이름이 자동으로 완성된다. 두 번 세 번 누르면 Py 로 시작하는 다른 폴더나 파일이 나타날 것이다. 이 방식으로 쉽게 디렉토리를 이동할 수 있다.
  • 콘솔을 통해 이 폴더 저 폴더를 다닌다는 것은 그만큼 컴퓨터의 파일 시스템을 여기 저기 엿볼 수 있는 기회가 된다. 특히 나중에 데이터를 파일에 저장하고 싶은 경우가 생길 텐데, 그 때 상당히 도움이 될 수 있다.
  • mac의 경우에는 터미널을 통해 문제를 수정하거나 숨겨진 설정을 변경하는 경우가 종종 있다. 터미널을 사용하는 방법을 조금 익혀두는 것은 자기 컴퓨터를 관리하는 능력을 약간 더 향상 시키는 셈이다.
  • 파이썬으로는 GUI가 있는 프로그램을 만들기는 좀 어렵지만, 명령줄 프로그램은 간단한 경우 단 몇 줄의 코드로도 만들 수 있다. 실제로 구동 화면이 없는 이런 프로그램들에 대해 실제로 파이썬은 아주 “많이 쓰이는” 인기 있는 언어이다. (구글 서버의 많은 프로그램들도 파이썬으로 만들어서 사용되고 있다.)

ex08.py

이번에는 위의 두 예제를 결합했다. 먼저 코드를 보자.

from sys import argv

script, user_name = argv
prompt = '> '

print "Hi %s, I'm the %s script." % (user_name, script)
print "I'd like to ask you a few questions."
    print "Do you like me %s?" % user_name
likes = raw_input(prompt)

    print "Where do you live %s" % user_name
lives = raw_input(prompt)

    print "What kind of computer do you have?"
computer = raw_input(prompt)

    print """
    Alright, so you said %r about liking me.
    You live in %r. Not sure where that is.
    And you have a %r computer. Nice.
    """ % (likes, lives, computer)

ex07.py와 같은 방식으로 실행해보자. python ex08.py sooop 이라고 치니 다음과 같이 표시된다.

c:\Apps\textfiles>c:\Python27\python.exe ex08.py sooop
Hi sooop, I'm the ex08.py script.
I'd like to ask you a few questions.
Do you like me sooop?
> Yes
Where do you live sooop
> Seoul
What kind of computer do you have?
> NG

Alright, so you said 'Yes' about liking me.
You live in 'Seoul'. Not sure where that is.
And you have a 'NG' computer. Nice.

코드는 별다르게 분석할 것이 없을만큼 간단한 내용이다. ex08.py의 각 라인의 위에 #을 넣어 바로 아래줄이 어떤 역할을 하는지 주석을 달아보자. 자신이 작성한 코드를 이런 식으로 다시 분석하는 것은 프로그래밍을 배우는 속도를 높이는데 큰 도움이 될 수 있다. 또한 작성한 코드를 소리내어 읽어보는 것 또한 도움이 될 수 있다. (익숙해지면 잘 알지 못해도 잘 아는 것처럼 느끼는 심리때문이다.)

이번 시간의 내용을 다시 한 번 정리하자.

  • 사용자의 입력은 프롬프트를 통해 직접, 그리고 매번 입력받는다. raw_input() 명령을 사용한다.
  • 입력받은 값은 ‘문자열’이다. 포맷팅에서 %s를 사용하고 있다.
  • 파라미터는 sys 모듈의 argv 모듈을 사용해 얻을 수 있다. 스크립트의 이름부터 그 뒤로 일련의 문자열들을 받아올 수 있다.
  • 콘솔 (도스창이나 터미널)의 기본적인 사용방법을 알아두자. (이는 기회가 있으면 글을 추가하겠다.)

[Python101] 002. 변수, 변수를 출력해보다.

파이썬 강좌 세 번째 시간이다. 이번에는 변수란 무엇이고 변수는 출력과 무슨 관계가 있는지를 알아보도록 하자.

초등학교 국어책에는 사진을 보여주고 빈칸에 알맞는 낱말을 넣는 문제들이 종종 나온다.

철수가  ____  봅니다.

이 빈칸에 무엇을 추가해주면 그 때마다 이 문장은 다른 문장이 될 수가 있다.

  1. 철수가 만화책을 봅니다.
  2. 철수가 영화를 봅니다.
  3. 철수가 재미를 봅니다.
  4. 철수가 미쳤나 봅니다.

아무래도 상황에 맞게 가변적인 내용을 출력해주는게, 조금 더 유연하고 쓸모있는 프로그램이 될 수 있는 소지가 클 것이다. 매번 똑같은 말만 나오는 건 좀 재미가 없으니까.

변수

그래서 변수에 대해 알아보도록 하자. 변수는 어떤 값을 담아두는 상자 같은 것이다. 담아두는 값에 따라서 변수는 그 내용이 달라질 수 있다. 따라서 가변적인 처리, 계산등을 할 수 있는 것이다. 변수는 프로그래밍에서 너무나 기본적인 것이라 뭐라 적절하게 설명할 말을 못 찾겠다. 아무튼 우리는 앞으로 변수는 많이, 정말 많이 사용하게 될 것이다.

그런데 조금 주의할 게 있다. 앞서 “변수는 어떤 값을 담아두는 상자”라고 했는데, 이는 사실 나중에 혼란을 줄 수 있는 틀린 표현이다. 개념적으로는 “어떤 값에 대해 이름표를 붙여둔다”라고 생각하는 것이 정확하다.

서점이나 도서관을 예로 들어보자. 도서관에는 많은 책이 있다. 정말 정말 많은 책이 있다. 우리가 도서관에 가서 책을 찾아보고자 할 때 검색을 해 보면 “서지번호”라는 것을 찾게 된다. 이 서지번호에 따라서 책을 찾을 수 있게 된다. 즉 변수는 ‘서지 번호’에 해당한다. 어떤 값에 이름표를 붙여두고, 나중에 다시 찾기 쉽게 표시를 해 두는 것이다. 사실상 ‘그릇에 담는’ 비유와 실질적, 체감적으로는 차이를 인지하기 어려울 수도 있는데, 일단은 그렇게 알아두자. 변수는 값을 담는 그릇이라기보다는 “값을 가리키는” 이정표나 명찰에 더 가까운 개념이다.

변수는 먼저 정의해두고 나중에 그 이름으로 값을 사용하게 된다. 변수를 정의하는 방법은 다음과 같다.

변수이름 = 값

즉 변수 이름에 값을 대입할 때는 등호를 사용한다. 이는 두 개가 같다는 의미가 아니라 변수에 값을 대입한다는 의미이다. (나중에 알게 되겠지만 두 개가 같다는 의미는 == 로 표현한다.) 자 그럼 이제 두 번째 예제인 ex02.py를 작성해 보도록 하자. 요상하게 생긴 표현들이 좀 나온다만 당황하지 말고 우선 “정확하게 타이핑”하고 보도록 하자.

ex02.py

#-*-coding:utf-8

number_of_apple = 50

print number_of_apple
print "Number of apples: ", number_of_apple

people = 5
print "Number of people: ", people
print number_of_apple / people

apple_per_person = number_of_apple / people
print "We can have ", apple_per_person, "apples for everyone."

print
print

# use formatting string
print "There are %d apples in the box" % number_of_apple
print "And here are %d people." % people
print "So, we can have %d apples for everyone." % apple_per_person

print
print

# use formatting string together
print "There are %d apples and we are %d person. \nSo, we can have %d apples for everyone." % (number_of_apple, people, number_of_apple / people)

실행해보면 다음과 같은 결과를 볼 수 있다.

50
Number of apples:  50
Number of people:  5
10
We can have  10 apples for everyone.

There are 50 apples in the box
And here are 5 people.
So, we can have 10 apples for everyone.

There are 50 apples and we are 5 person.
So, we can have 10 apples for everyone.

결과를 보고 나서 다시 한 번 작성한 코드를 이해할 수 있는지 찬찬히 읽어보자. 코드를 읽어보고 무슨 의미일지 생각해본 다음 아래 설명을 보도록 한다.

1) number_of_apple = 50 : 이 문장은 number_of_apple 이라는 변수에 50이라는 값을 대입한다. 즉 숫자값 50에 number_of_apple 이라고 이름표를 붙여 주었다.

변수의 이름은 영문자와 언더스코어(흔히 언더바라고 부르는 _ )그리고 숫자로 구성될 수 있다. 변수 이름에 숫자를 쓰는 것은 그리 좋은 습관이 아니며, 가능하면 간략하고 실제로 어떤 문맥적인 의미를 갖는 한개 혹은 두세개의 단어를 사용하는 것이 좋다. 귀찮다는 이유로 a = 50, u = 70 이런 식으로 쓰는 사람이 많은데, 나중에 이 변수가 무슨 의미인지를 도통 알 수 없게 되는 경우가 많기 때문에 가능하면 단어를 그대로 쓰는 것을 추천한다. 또한 여러 단어를 하나로 합성할 때에는 공백 대신 언더스코어를 써서 변수 이름 자체는 한 단어가 되도록 해야 한다. 혹은 이런 방법 대신에 numberOfApple 과 같은 식으로 두 번째 단어부터는 각 단어의 첫글자를 대문자로 쓰는 표기법도 있다. (아이폰 앱을 만드는 Objective-C 와 같은 언어는 이런 표기법을 추천하고 있다.) 또한 변수명은 숫자로 시작해서는 안된다. 대부분의 프로그래밍 언어가 숫자로 시작하는 이름을 허용하지 않고 있다.

2) 5행은 따옴표 없이 변수 이름을 사용하여 print 하고 있다. 이는 변수의 이름이 아닌 변수의 내용물, 즉 변수가 가리키는 값을 출력해주도록 한다. 사실 print 문은 “계산식”의 결과를 출력하는 개념이라고 이해하면 된다. 변수의 이름만 쓴 계산식은 결국 변수의 값을 말하는 것이니까. print 문은 계산식의 결과를 표시하므로 당연히 다음의 구문을 쓸 수 있다.

print number_of_apple * 10

3) 2)번을 이해했다면 6번 행은 보다 명쾌하게 이해가 될 것이다. 즉 문자열을 출력하고 컴마로 연결했는데, 이이서 변수의 값을 출력해주고 있다.

4) 8~10 행은 다른 변수, people 이라는 변수를 정의하고 출력한다. 그런 다음, 사과의 수를 사람 수로 나눈 수식값을 출력한다. 13행은 문자열과 계산식(변수값), 다시 문자열을 컴마로 연결하여 출력해주는 예를 보여준다.

5) 19~21행은 되게 이상해보이는 구성을 가지고 있다. 먼저 문자열의 내용을 살펴보면 문자열 안에 숫자가 들어가야 할 부분에 %d 라고 써 두었다. 그런 다음 문자열의 뒤에 % 를 붙이고 변수 명을 넣었다.

우리는 이런 것을 ‘문자열 포맷팅’이라고 부른다. 문자열에 특정한 서식을 적용하고, 그 서식에 맞는 값을 치환하여 표시하도록 하는 것이다. 즉 %d 라는 문자는 numbers_of_apple의 숫자값이 치환되어 표시된다. 나머지 두 행도 동일한 방식으로 표시하고 있다.

문자열 포맷팅에서 %d는 digit의 의미로, 숫자를 의미한다. 이와 비슷한 포맷 문자에는 몇 가지가 있는데 가장 흔하게 쓰이는 것들을 소개하겠다.

  • %d : 숫자
  • %f : 소수점이 있는 숫자.
  • %c : 한 글자
  • %s : 문자열
  • %r : 뭐든 상관없음. 변수를 print 한 결과로 치환됨.

6) 이러한 포맷팅이 유요한 것은 마지막 27행에서 드러난다. 27행은 하나의 문자열 안에 이런 치환자를 3개 쓰고 있다. 그리고 문자열 뒤에는 % 를 쓰고 다시 괄호속에 순서대로 들어갈 값을 써주고 있다. 이 때 치환자의 개수와 괄호안의 수식의 개수는 같아야 한다.

다시 한 번 말하지만 포맷팅은 처음에는 이상하게 보여도, 출력하는 용도등으로 쓸 텍스트를 ‘합성’해내는 좋은 방법이다. 익숙해지면 그리 이상하게 보이지도 않고, 또한 어렵지도 않다.

문자열 포매팅

방금 ex02.py를 통해 문자열을 포매팅하는 법을 잠깐 살펴보았다. 포매팅은 문자를 출력하는 것 외에도 문자열을 합성하는데도 유용하게 쓸 수 있다고 했다.

포맷팅 문자열을 만드는 방법은 다음과 같다.

“%d….%f… %r…. %s…” % 치환될 값1, 치환될 값2 ,….)

문자열에 치환자를 포함시키고 문자열 뒤에 %를 표시해서 치환될 값의 묶음과 연결해주면 된다. 그리고 치환될 값이 숫자인지, 소수점을 포함하는 숫자인지, 문자열인지 등에 따라 적절한 치환자를 쓸 수 있으면 되는 것이다.

그럼 이번에는 몇 가지 포매팅을 활용하는 기법을 좀 더 보도록 하자.

ex03.py

ex03.py는 포맷팅을 사용하여 문자열을 합성하고 출력하는 방법을 보여준다. 특이할만한 점은 ‘포맷팅 문자열’ 자체를 변수에 담아두고 출력할 때 합성하는 방법을 쓸 수도 있다는 점이다.

#-*-coding:utf-8

my_name = "sooop"
height = 180
weight = 100
eye = 1.5

print "My name is %s." % my_name
print "I'm %dcm tall and weight %d kg." % (height, weight)
print "My Eyes are %f. I don't need glasses." % eye

print

# string with format
greeting = "Hi, my name is %s" % my_name
print greeting
print

# use format string
more_greet = "Hi, my name is %s. \nI'm %dcm tall and weight %dkg."
print more_greet % (my_name, height, weight)

위의 ex02.py와 마찬가지로 코드의 각 부분이 어떤 의미인지 유추해보고 어떻게 표시될 지 추측해보자. 그리고 실행해보면 다음과 같은 결과가 보이는데, 예상대로 인지 확인해보자.

My name is sooop.
I'm 180cm tall and weight 100 kg.
My Eyes are 1.500000. I don't nee

Hi, my name is sooop

Hi, my name is sooop.
I'm 180cm tall and weight 100kg.

1) 3행에서 이번에는 my_name 이라는 변수에 문자열을 대입했다. 그리고 이를 8행에서 출력한다.

2) 중요한 부분은 15행부터이다. 15행은 print 문이 아니다. greeting 이라는 변수를 정의하면서 이 변수에 포맷 문자열에 다른 변수 값을 합성하여 그 결과를 대입하고 있다. 따라서 greeting은 이 때 “Hi, my name is sooop.”이라는 문자열을 가리키게 된다.

3) 20행에서는 포맷 문자열 그자체를 변수에 대입했다. 21행에서 more_greet 변수 뒤에 치환될 값을 붙여주었다. 따라서 출력되는 시점에 문자열이 합성되고 이를 출력하게 되었다.

ex04.py

한가지 예제를 더 살펴보기로 하자.
# -*-coding:utf-8-*-
print "Mary had a little lamb."
print "Its fleece was white as %s." % 'snow'
print "And everywhere that Mary went."
print "." * 10 # ????

end1 = "C"
end2 = "h"
end3 = "e"
end4 = "e"
end5 = "s"
end6 = "e"
end7 = "B"
end8 = "u"
end9 = "r"
end10 = "g"
end11 = "e"
end12 = "r"

print end1 + end2 + end3 + end4 + end5 + end6,
      print end7 + end8 + end9 + end10 + end11 + end12

당연하다고 생각할 수도 있겠지만, 파이썬에서는 “문자열에 대한 연산”을 지원한다. 사실 포매팅 문자열 역시 문자열에 대한 연산인 셈이다. (포맷 문자열만 변수에 저장했다가 print 시에 연산하는 것 처럼 이해할 수 있다.) 3행을 보면 실제로 포매팅 문자열에 치환 값으로 변수가 아닌 문자열 상수를 넣고 있다. 이런 식으로 2개의 문자열을 합성하는 것이 가능하다.

특히 문자열에 대해 +, * 연산이 가능하다. 문자열을 더하면 문자열끼리 연결되고, 숫자를 곱하면 곱한 숫자값만큼 반복된다는 것을 알 수 있다. 표시되는 결과는 다음과 같다.

Mary had a little lamb.
Its fleece was white as snow.
And everywhere that Mary went.
..........
Cheese Burger

포맷팅 문자열을 사용하는 것은 상당히 쓸모가 많은데, 다음 ex05.py를 통해서 한가지만 더 살펴보기로 하자.

ex05.py

formatter = "%r %r %r %r"

print formatter % (1, 2, 3, 4)
print formatter % ("one", "two", "three", "four")
print formatter % (True, False, False, True)
print formatter % (formatter,   formatter,  formatter,  formatter)
print formatter % (
        "I had this thing.",
        "That you could type up right.",
        "But it didn't sing.",
        "So I said goodnight."
        )

포맷팅 문자열을 변수에 대입한 후 여기에 다양한 치환값을 넣어 매번 다르게 표시하고 있는 것을 확인할 수 있다. 이 예제의 출력은 쉽게 예상할 수 있을 것이다.

1 2 3 4
'one' 'two' 'three' 'four'
True False False True
'%r %r %r %r' '%r %r %r %r' '%r %r %r %r' '%r %r %r %r'
'I had this thing.' 'That you could type up right.' "But it didn't sing." 'So I said goodnight.'

상당히 긴 글이 된 관계로 잠깐 요약을 하고 마무리하겠다. 기본적인 원리와 문법에 대해서는 꼭 기억해야 한다.

  • 문자열 포맷팅은 문자열과 다른 값을 합성하는 방법이다.
  • 문자열 포매팅과 더하기, 곱하기 등은 문자열에 대한 연산이다.
  • 문자열 포매팅은 문자열 % (치환값, 치환값…)의 문법을 사용한다.
  • 변수는 어떤 값을 가리키는 이름표이다.

[Python101] 001. 문자를 출력해보다.

출력해보기

아마도 C언어가 세상에 알려질 때 “Hello World!”라는 문장을 출력하는 시연을 했던 것이 시초가 되어 프로그래밍 언어를 시작하는 개발자들은 맨 먼저 이 문장을 출력해보는 코드를 작성하곤 한다고 한다. 이는 단순히 관습이라기보다는 보다 중요한 의미를 갖는다. 프로그램은 기본적으로 “어떤 처리를 해주는 기계 장치”에 가까운 개념이다. 그러니까 입력→처리→출력의 과정을 통해서 작업을 수행한다.

문자열을 찍어서 표시하는 기능은 이 출력의 중요한 부분을 차지하게 된다. 그런데 문제는 뭔가를 ‘출력’할 때는 그 표현 양식이 중요하다는 점이다. 그래서 프로그래밍 언어마다 문자열을 포매팅(서식화)하는 부분은 나름 상당히 중요하게 다뤄지고 있고, 이 부분은 깊게 공부하고자 한다면 상당히 살펴야 하는 분량이 많다. (문자열을 다루는 것 자체가 생각보다 범위가 많고 또 그만큼 중요하다.) 따라서 프로그래밍을 통해 실제로 쓸모 있는 것을 만드는 것을 가정한다면 입출력과 관련한 부분은 꽤나 중요하다고 볼 수 있다. 그래서 다른 개념들에 앞서서 이 부분을 좀 먼저 다뤄 봐야 할 것 같다.

ex01

가장 먼저 print 명령에 대해 살펴보도록 하겠다. print 명령은 정해진 문자열을 콘솔 화면에 출력해주는 명령이다.

print {출력할 것}

위와 같은 형식으로 쓰며, 실제로 중괄호 {}는 쓰지 않는다. 이 중괄호는 명령이나 구문에서 직접 넣어줘야 하는 것을 의미하는 형식상의 표현이라 보면 된다.

우리가 (공식적으로는) 처음으로 작성해볼 ex01.py는 간단히 텍스트를 출력해주는 프로그램이다. 한줄 한줄 정확하게 타이핑해 보도록 하자. (화면이 좁아 읽기 불편하다면 텍스트 편집기에 붙여 넣은 다음, 실제로 그 내용을 보면서 꼭 직접 타이핑하도록 한다. 맥용 IDLE에서는 한글 입력이 안되는 문제가 있는데, 불가피한 경우에는 텍스트 에디터에서 작성 후 IDLE에서 붙여 넣자.)

#!/usr/bin/python
#-*-coding:utf-8

# 1번 행은 터미널에서 바로 실행될 수 있도록 함
# 2번 행은 주석이나 문자열에 한글을 쓸 수 있도록함
# 윈도의 경우에는 -*-coding:cp949 로 해야 함

# 문자열을 출력할 때는 print 명령을 사용한다.
# 문자열은 겹따옴표나 홑따옴표로 둘러싸게 된다.

print "Hello World!"
print 'Hello World!'

# 위 두 문장은 똑같은 결과를 출력한다. 차이가 있는지?

print
print
# print 만 쓴 문장은 빈줄을 출력한다.

print "You're typing your first python program."
print 'He said "Good morning." and waved to me.'

# 위 두 문장은 무슨 차이가 있는지? 따옴표의 종류에 주목할 것

# using escape characters

print "That's The \"GREATEST\" program."

# another escape charaters
print
print
print "This line is printed in \n2 lines."
print "\tAnd this line is printed with indentation."
print "You can also print\n\t* a kind of\n\t* list\n\t* like this way."
print "\n\nIf you want to print 'back slash', use escape character : \\\\"

# 파이썬은 긴 문자열을 출력할 때 이렇게 쓸 수도 있음

print """You can print multi-line text, with triple double-quotes
like this. print 2, 3, 4 ,5 or more line as you type.
You can also using \\ escape character \\ in this representation.
and "Qouted Sentence using 'qoutes' is also available."."""

# 마지막으로 재밌는 표현하나더
print '.' * 20

위 코드를 정확히 타이핑했다면, 실행 후 다음과 같은 내용을 볼 수 있을 것이다.

Hello World!
Hello World!

You're typing your first python program.
He said "Good morning." and waved to me.
That is 'The "GREATEST" program.

This line is printed in
2 lines.
And this line is printed with indentation.
You can also print
    * a kind of
    * list
    * like this way.

If you want to print 'back slash', use escape character : \\
You can print multi-line text, with triple double-quotes
like this. print 2, 3, 4 ,5 or more line as you type.
You can also using \ escape character \ in this representation.
and "Qouted Sentence using 'qoutes' is also available.".
....................

1) # 문자로 시작하는 행은 주석(코멘트)이다. 주석은 프로그램 실행에 아무런 영향을 주지 않는다. 대신 나중에 작성된 코드를 다시 읽어볼 때 이 부분은 무엇을 하는 부분인지 쉽게 알아보기 위해 메모를 할 때 사용할 수 있고, 혹은 문제가 있는 코드를 무력화할 때 사용하기도 한다. 주석에 대한 내용은 뒤에서 다시 살펴보게 될 것이다.

2) 처음 2줄의 주석은 파이썬에서 특별한 장치이다. 1행은 파이썬이 설치된 경로를 알려주어 터미널에서 파이썬 코드가 바로 실행될 수 있도록 한다. (이 부분 역시 다음에 따로 설명하겠다.) 2행은 이 코드의 문자가 UTF-8로 인코딩된 문자라는 것을 나타낸다. 주석등에 영문자, 숫자 등이 아닌 한글이나 한자, 일본어 등이 들어갈 때 파이썬에게 알파벳 말고 다른 문자가 있다는 것을 알려준다고 보면 된다.

3) Hello World! 를 출력하는 각각의 print 명령문이 있다. 두 개는 결과적으로 동일한 출력을 하지만 따옴표를 겹따옴표(“)를 썼는지 홑따옴표(‘)를 썼는지 차이가 있다. 이 따옴표의 차이는 다시 아래에서 볼 수 있다.

4) print 문에 아무 것도 넣지 않는다면 그냥 빈 줄을 출력하게 된다.

5) 20~21 행 두 줄은 따옴표의 용도를 잘 설명해주고 있다. 문자열은 따옴표 안에 들어가게 되므로 만약 문자열 내에 겹따옴표가 있다면 홑따옴표를, 홑따옴표가 있다면 겹따옴표를 써서 문자열을 감싸야 한다. (열고 닫는 따옴표의 쌍을 제대로 맞추기 위해서이다.)

6) 만약, 문장 내에 겹따옴표와 홑따옴표를 같이 써야 한다면 어떻게 해야 할까? 만약 “That’s “The GREATEST” program.” 이라고 쓰면 따옴표는 괄호의 짝처럼 행동하므로 “That’s “The GREATEST” program.” 으로 두 개의 문자열 사이에 The GREATEST가 들어가서 오류가 나게 된다. 이렇게 파이썬에서 사용하는 문법과 관련된 문자들은 따로 특별한 처리를 하지 않으면 문자열 내에서는 사용할 수 없다. 따라서 따옴표를 문자열의 시작과 끝을 알리는 용도가 아니라 글자 그대로의 따옴표로 인식하게 하기 위해서 ‘이스케이프 문자’라는 것을 사용한다. 이는 문자 앞에 역슬래쉬(\ : 윈도 운영체제에서는 원화 표시로 표시됨)를 붙여서 사용한다. 즉 \” 이라고 쓰면 문자열을 닫는 따옴표가 아니라 문자열 내에서 따옴표 한 글자로 인식한다.

7) 32~35행은 이런 이스케이프 문자를 사용하는 몇 가지 예를 보여준다. 이스케이프 문자를 표시하는 역슬래쉬는 문장 내에서 쓰이면 마찬가지로 역슬래쉬 두개를 붙여 하나의 문자로 표시하면 된다. 이스케이프 문자는 그 외에 특수한 문자들을 대체하기도 한다. \n은 “New line”의 의미로 문자열 내에서 줄바꿈을 넣어준다. 그리고 \t는 “Tab”으로 탭 키를 눌러 들여쓰기를 한 효과를 보여준다.

8) 파이썬에서는 “여러 줄의 텍스트”를 하나의 문자열로 만드는 방법이 있다. 바로 겹 따옴표를 세번 연달아 쓴 것을 문자열의 앞,뒤에 붙여주는 것이다. 이렇게 만든 문자열은 우리가 타이핑한 그대로를 보여주기에 적합하다. 즉 여러 줄의 문장을 출력해야 하는 경우에는, 이 방법을 사용하면 print 문을 반복하지 않고 한 번에 많은 양의 텍스트를 출력할 수 있다. 물론 이 경우에도 이스케이프 문자를 사용하여 들여쓰기나 줄바꿈을 넣는 것이 가능하다.

특히 “”” ~ “”” 로 감싼 경우에는 문자열의 시작과 끝이 연속되는 따옴표 세 개 이기 때문에 겹따옴표나 홑따옴표를 이스케이프 문자로 처리하지 않고도 사용할 수 있게 된다.