CodeOnWeb
Log in

챕터 1. 첫 파이썬 프로그램

본격적으로 파이썬 프로그래밍의 세계에 들어가봅시다.

Park Jonghyun 2015/09/03, 13:15

Contents

파이썬 3에 뛰어들기 (22)

챕터 -1. “파이썬 3로 뛰어들기”에서 달라진 점 챕터 0. 파이썬 설치하기 챕터 1. 첫 파이썬 프로그램 챕터 2. 고유 자료형 챕터 3. 컴프리헨션(Comprehensions) 챕터 4. 문자열(Strings) 챕터 5. 정규표현식(Regular Expressions) 챕터 6. 클로저와 제너레이터(Closures & Generators) 챕터 7. 클래스와 반복자(Classes & Iterators) 챕터 8. 고급 반복자(Advanced Iterators) 챕터 9. 단위 테스트(Unit Testing) 챕터 10. 리팩토링(Refactoring) 챕터 11. 파일 챕터 12. XML 챕터 13. 파이썬 객체 직렬화 챕터 14. HTTP 웹서비스 챕터 15. 사례 연구: chardet을 파이썬 3로 이식하기 챕터 16. 파이썬 라이브러리 패키징하기 부록 A. 2to3를 이용해서 코드를 파이썬 3로 이식하기 부록 B. 특수 함수 이름 부록 C. 이제 어디로 가야 할까요? 부록 D. 문제 해결

당신의 짐을 고요한 침묵속에 묻어두지 마라. 문제가 있는가? 좋다. 기뻐하고, 뛰어들어, 탐구하자!
— 헤네폴라 구나라타나(Ven. Henepola Gunaratana)

뛰어들기

관습대로라면 좀 지루하더라도 프래그래밍의 기초가 되는 요소를 먼저 설명하고 나서 천천히 유용한 무언가를 만들어야 합니다. 여기서는 다 생략하고, 제대로 작동하는 완전한 파이썬 코드를 먼저 봅시다. 아마 전혀 감을 못 잡을 수도 있어요. 하지만 걱정마세요. 한 줄 한 줄 분석해 볼테니까요. 일단 한 번 주욱 읽고 이해할 수 있는 부분이 있는지 살펴보세요.

이제 이 프로그램을 커맨드라인에서 실행해 봅시다. 윈도우즈에서는 아래처럼 되겠죠?

맥 OS X나 리눅스에서는 대충 이럴거에요.

CodeOnWeb에서는 RUN 버튼을 눌러 바로 결과를 볼 수 있습니다. 이렇게 나옵니다.

축하 드립니다. 짝짝짝. 여러분은 처음으로 파이썬 프로그램을 실행했습니다. 커맨드라인에서 파이썬 실행기를 부르고 실행할 파이썬 스크립트 파일의 이름을 넘겨 줬습니다. 스크립트에는 approximate_size()라는 함수가 있는데, 바이트로 된 파일 크기를 읽어서 보기 좋은 근사치 형식으로 변환하는 일을 합니다. (이런 기능을 윈도우즈 탐색기나 맥 OS X의 파인더, 혹은 리눅스의 노틸러스, Dolphon, Thunar 등에서 보신 일이 있을거에요. 문서가 있는 폴더에서 자세히 보기를 선택하면 문서의 아이콘, 이름, 크기, 형식, 최근 수정일 등을 볼 수가 있지요. 만약 폴더에 크기가 1093 바이트인 TODO라는 파일이 있다면, TODO 1093 bytes 대신 TODO 1 KB와 같은 식으로 나타납니다. 이런 것이 approximate_size() 함수가 하는 일입니다.)

스크립트 아래쪽을 보면 print(approximate_size(arguments)) 형식으로 쓰여진 두 개의 호출문을 볼 수 있습니다. 함수 호출이라는 것인데, approximate_size() 함수에 인자(arguments)를 넘기면서 호출하고, 반환된 결과값을 바로 print() 함수에 넘겼습니다. print() 함수는 인자의 내용을 화면에 출력하는 함수인데, 파이썬에 내장된 함수이므로 따로 선언할 필요가 없습니다. 언제, 어디서든 그냥 쓰면 되요. (파이썬에는 많은 내장 함수와, 모듈에 나누어져 있는 그보다 훨씬 더 많은 함수를 제공합니다. 조금만 참으세요. 먼저 공부하던 것부터 끝내자구요.)

그런데 이 스크립트를 실행시키면 왜 항상 같은 결과가 나올까요? 이제부터 이것에 대해 알아볼 겁니다. 먼저, approximate_size() 함수를 봅시다.

함수 선언

파이썬에도 대부분의 다른 언어와 마찬가지로 함수가 있습니다. 하지만 c++처럼 별도의 헤더 파일도 없고, 파스칼처럼 interface/implementation 섹션도 없습니다. 함수가 필요하면 그냥 다음과 같이 선언하세요:

def라는 키워드로 함수를 선언을 시작하고, 그 뒤에 함수 이름과 괄호로 묶인 인자가 옵니다. 인자가 여러개일 경우 쉼표로 구분합니다.

함수 반환값의 자료형(datatype)을 따로 지정하지 않는 점을 눈여겨 보세요. 심지어 반환값이 있는지 없는지도 저정하지 않습니다. (사실 모든 파이썬 함수는 반환값이 있습니다. 함수 내에서 return 문을 만나면 return 오른쪽에 쓰인 값을 반환하고, return 문이 없다면 None이라는 파이썬의 null을 반환합니다.)

몇몇 언어에서는 반환값이 있으면 function이라는 키워드로, 반환값이 없다면 서브루틴(subroutine)이라는 의미의 sub로 구분해서 선언하기도 합니다. 파이썬에는 서브루틴이 없습니다. 모든 것은 함수입니다. 또 모든 함수는 값을 반환하고(None을 포함하서), def로 선언합니다.

approximate_size() 함수는 size와 a_kilobyte_is_1024_bytes라는 두개의 인자를 받는데, 두 인자 모두에 자료형을 지정하지 않았습니다. 파이썬에서는 변수의 자료형을 별도로 선언하지 않습니다. 파이썬이 변수의 형태를 내부적으로 판단해서 기억하고 있기 때문입니다.

Java와 같은 정적 타입 언어에서는 함수 반환값과 모든 인자의 자료형을 반드시 명시해야 하지만, 파이썬에서는 따로 자료형을 명시할 필요가 없습니다. 변수나 함수에 할당된 값을 통해 내부적으로 자료형을 알아내고 저장하기 때문입니다.

선택 인자와 이름을 가지는 인자

파이썬 함수의 인자는 기본값을 가질 수 있습니다. 만약 함수가 호출될 때 인자가 생략되었다면, 그 인자는 기본 값으로 설정됩니다. 또한, 함수를 호출할 때 인자에 이름을 지정하면 인자의 순서도 마음대로 바꿀 수 있습니다.

approximate_size() 함수의 선언부를 다시 한 번 살펴보죠.

두 번째 인자인 a_kilobyte_is_1024_bytes는 기본값이 True로 설정되어 있습니다. 이는 함수를 호출할 때 이 인자를 생략하고 호출할 수 있다는 뜻이며, 그 값은 자동으로 True가 됩니다.

이제 스크립트의 아래쪽을 볼까요.

  1. approximate_size() 함수를 호출할 때 두 개의 인자를 전달했습니다. 두 번째 인자의 값으로 False를 지정했으므로 approximate_size() 함수 안에서 a_kilobyte_is_1024_bytes의 값은 False가 됩니다.
  2. 여기서는 approximate_size() 함수를 호출할 때 하나의 인자만 전달했습니다. 두 번째 인자는 필수가 아니가 때문에 그래도 괜찮습니다. 호출 시 값이 없으므로 두 번째 인자는 함수 선언에 정한대로 True 값을 가지게 됩니다.

함수를 호출할 때 인자의 이름을 정할 수도 있습니다.

  1. approximate_size() 함수를 호출할 때 첫 번째 인자(size)에 4000을 주고 a_kilobyte_is_1024_bytes라는 이름의 두 번째 인자에는 False를 주었습니다.
  2. approximate_size() 함수를 호출할 때 size 인자에 4000을, a_kilobyte_is_1024_bytes에는 False를 주었습니다. (이름을 가지는 인자들이 함수에 선언된 인자의 순서와 같은 순서를 가지지만, 사실 순서는 중요하지 않습니다.)
  3. approximate_size() 함수를 호출할 때 먼저 a_kilobyte_is_1024_bytes에 False를 주고, 두 번째 인자로 size에 4000을 주었습니다. (순서는 중요하지 않다고 했죠?)
  4. 이렇게 호출하면 오류가 발생합니다. 이름을 가지는 인자 뒤에 이름이 없는(위치에 의해 식별되는) 인자가 있기 때문입니다. 인자는 왼쪽에서 오른쪽으로 읽혀지고, 그 중간에 이름을 가진 인자가 있으면 그 우측의 인자에도 반드시 이름을 주어야 합니다.)
  5. 이 호출 역시 4번과 같은 이유로 실패합니다. 놀라셨나요? 어쨌든 size 인자에 4000을 주었고, 그 뒤의 False는 a_kilobyte_is_1024_bytes에 들어가야 할 값이라는 게 분명합니다. 하지만 파이썬은 그렇게 작동하지 않습니다. 이름을 가진 인자가 일단 하나 있으면 그 뒤에 나오는 인자에도 이름을 지정해야 합니다.

쉽게 읽히는 코드 작성하기

코드 문서화의 중요성에 대해 지루하게 설명드리고 싶지는 않습니다. 다만 이것만은 기억하세요. 한 번 작성된 코드는 후에도 여러 번 읽히게 되고, 가장 중요한 독자는 여러분 자신이라는 것을요. 코드를 작성하고 6개월 뒤에 모든 것을 잊어버린 후 무언가를 고쳐야 되는 상황을 생각해보세요. 파이썬은 읽기 쉬운 코드를 작성을 돕는 여러 기능을 탑재하고 있으니 잘 써먹읍시다. 6개월 안에 제게 감사하게 될거에요.

Documentation Strings

함수에 설명을 달고 싶으면 documentation string(줄여서 docstring이라고 합니다)을 이용하면 됩니다. 위의 예제 코드에서 approximate_size() 함수는 docstring을 가지고 있습니다.

따옴표 세 개를 쓰면 여러 줄에 걸쳐 docstring을 달 수 있습니다. 시작과 끝 부분에 있는 세겹 따옴표 사이의 모든 내용(줄바꿈, 공백, 또 다른 따옴표 등을 포함해서)은 하나의 docstring으로 간주됩니다. 세겹 따옴표를 이용한 주석은 코드 어느 부분에서나 사용할 수 있지만, 함수의 docstring 정의에 가장 많이 쓰입니다.

세겹 따옴표를 이용하면 홑따옴표와 겹따옴표가 포함된 문자열을 쉽게 정의할 수 있습니다. 펄(Pearl) 5의 qq/.../ 처럼 말이지요.

세겹 따옴표 사이에 있는 모든 내용은 함수의 docstring입니다. 함수가 하는 일에 대해 적어둔 곳이지요. Docstring은 함수 내에서 가장 먼저 정의됩니다 (즉, 함수 선언 바로 다음 줄에 위치합니다). Docstring을 정의하는 것이 의무는 아니지만 가능하면 달아주세요. 뭐 이런 이야기는 이미 귀가 따갑도록 들으셨겠지요. 하지만 docstring을 달면 좋은 점이 하나 더 있습니다. Docstring은 단순한 주석문이 이니라 함수의 속성(attribute)으로써, 런타임(runtime)에 호출할 수 있습니다.

많은 파이썬 통합개발환경(IDEs, Integrated Development Environments)에서 docstring을 적극적으로 활용하고 있습니다. 가령 함수 이름을 치기 시작하면 그 함수의 docstring이 툴팁으로 나타나기도 합니다. 매우 유용한 기능이지만, 여러분이 docstring을 작성하는 데 쏟은 정성만큼만 도움이 되겠지요.

import 검색 경로

더 나가기 전에 라이브러리 검색 경로에 대해 잠깐 짚어보겠습니다. 파이썬은 모듈을 import할 때 몇 가지 경로를 검색합니다. 정확히 말하면, sys.path에 정의된 모든 디렉토리를 뒤집니다. 이 목록은 리스트(list)로 저장되어 있기 때문에 일반적인 리스트 메소드(method)를 통해 쉽게 읽고 수정할 수 있습니다. (리스트에 대해서는 고유 자료형에서 자세히 알아보겠습니다.)

  1. sys 모듈을 import해서 그 안에 있는 모든 함수와 속성을 사용할 수 있게 만듭니다.
  2. sys.path에는 현재 검색 경로로 지정된 디렉토리가 리스트 형태로 저장되어 있습니다. (여러분의 운영체제나 파이썬 버전, 설치된 경로 등에 따라 출력되는 내용이 좀 다를 수 있습니다.) 여러분이 모듈을 import할 때 파이썬은 그 모듈과 같은 이름을 가진 .py 파일을 찾기 위해 이 디렉토리를 검색합니다.
  3. 사실 저 거짓말 했어요. 진실은 더 복잡합니다. 모든 모듈이 .py 파일로 저장되는 것은 아니라서요. 파이썬 내장 모듈은 파이썬 자체에 포함되어 있어요. 내장 모듈도 다른 모듈과 마찬가지로 동작하지만, 파이썬이 아닌 C로 작성되어 있기 때문에 소스코드를 볼 수는 없습니다. (파이썬도 C로 작성되었죠.)
  4. 런타임에 새로운 디렉토리를 sys.path에 넣어 파이썬 검색 경로에 추가할 수도 있습니다. 다음부터 모듈을 import할 때 그 디렉토리도 함께 검색합니다. 이는 파이썬이 실행되고 있는 동안만 유지됩니다.
  5. sys.path.insert(0, new_path)라고 쓰면 새로운 디렉토리를 sys.path 리스트의 첫 항목으로 추가할 수 있습니다. 그러면 그 디렉토리가 파이썬 검색 경로의 가장 앞에 위치하게 됩니다. 가능하면 이 방식으로 디렉토리를 추가하는 것이 좋습니다. 같은 이름의 모듈이 있어 충돌이 발생할 때(예를 들어, 파이썬 2에 특정 이름을 가진 라이브러리가 있는데, 같은 이름을 가진 파이썬 3의 모듈을 이용하고 싶을 때) 여러분이 추가한 디렉토리가 가장 먼저 검색되어 원하는 모듈을 사용할 수 있습니다.

모든 것은 객체다

잊어버리셨을지 모르겠는데, 파이썬 함수는 속성을 가지고 있고, 런타임에 그 속성을 사용할 수 있습니다. 함수는 파이썬의 다른 모든 것과 마찬가지로 객체입니다.

파이썬 대화형 쉘을 실행하고 다음 코드를 입력해보세요.

  1. humansize 프로그램을 모듈(필요시 다른 파이썬 프로그램에서 사용할 수 있는 코드의 묶음)로 import 합니다. 모듈을 import하면 그 모듈의 모든 공용(public) 함수나 클래스, 속성 등을 참조할 수 있습니다. 한 모듈에서 다른 모듈을 import 해 필요한 기능을 이용할 수도 있고, 파이썬 대화형 쉘에서도 모듈을 import할 수 있습니다. 이는 매우 중요한 개념인데, 앞으로 이 책을 읽어 나가면서 계속 마주치게 될 겁니다.
  2. import된 모듈에 정의된 함수를 사용하려면 모듈 이름을 앞에 같이 써야 합니다. 그냥 approximate_size라고 호출하면 안 되고 humansize.approximate_size와 같이 작성해야 합니다. 자바(Java) 클래스를 써봤다면 친숙한 표현이지요?
  3. 함수를 호출하는 대신 함수의 속성중 하나인 __doc__을 호출했습니다.

파이썬의 import는 펄(Pearl)의 require와 비슷합니다. 파이썬에서 모듈을 import 하면 module.function과 같은 식으로 함수를 호출할 수 있습니다. 펄에서 모듈을 require 하면, module::function을 이용해 함수를 호출합니다. 많이 닮았죠?

객체가 무엇이죠?

파이썬에 있는 모든 것은 객체이므로, 모든 것은 속성(attribute)과 메소드(method)를 가질 수 있습니다. 예를 들어, 모든 함수는 그 함수의 docstring을 반환하는 내장 속성인 __doc__을 가지고 있습니다. sys 모듈은 path라는 속성을 가지고 있는 모듈이지요 (물론 다른 속성도 있죠). 기타 등등.

여전히 가장 핵심적인 질문인 "객체가 무엇이죠?"라는 질문의 답으로는 부족한 것 같네요. 프로그래밍 언어마다 "객체"를 조금씩 다르게 정의합니다. 어떤 언어에서는 모든 객체가 반드시 속성과 메소드를 가져야 하고, 다른 언어에서는 하위클래스가 될 수 있어야 객체라고 정의합니다. 파이썬은 상당히 근본없...유연합니다. 객체는 속성과 메소드를 가지지 않을 수도 있고 가질 수도 있습니다. 모든 객체가 하위클래스가 되지도 않습니다. 하지만 변수에 할당될 수 있고 함수의 인자로 넘길 수 있다는 관점에서 볼 때 모든 것은 객체입니다.

아마 다른 프로그래밍 언어에서 "first-class object"라는 용어를 들어본 분이 있을겁니다. (역자 주: 객체가 할 수 있도록 정의된 모든 일을 제한없이 할 수 있는 객체. 이에 반해 부분적으로만 할 수 있는 객체를 second-class object라고 함) 파이썬 함수는 first-class object입니다. 한 함수를 다른 함수의 인자로 넘길 수 있습니다. 모듈도 first-class object입니다. 모듈 전체를 함수의 인자로 넘길 수 있습니다. 클래스(class)와 개별 인스턴스(instance) 역시 first-class object입니다.

파이썬에서는 모든 것이 다 객체다. 이 개념은 매우 중요하기 때문에 한동안 계속 떠들겁니다. 문자열은 객체입니다. 리스트도 객체입니다. 함수도 객체입니다. 클래스도 객체입니다. 클래스 인스턴스도 객체입니다. 심지어 모듈도 객체입니다.

코드 들여쓰기

파이썬의 함수에는 시작과 끝을 나타내는 표시가 없습니다. 다른 언어처럼 중괄호({})도 사용하지 않습니다. 파이썬의 함수는 콜론(:)과 코드 들여쓰기만을 이용하여 그 시작과 끝을 나타냅니다.

  1. 코드 블록은 들여쓰기에 의해 결정됩니다. "코드 블록"이라 함은, 함수, if문, for문, while문 등을 말하는 겁니다. 들여쓰기를 시작하면 블록이 시작되고, 다시 내어쓰면 그 블록이 끝납니다. 명시적인 괄호나 키워드를 따로 써주지 않습니다. 이 말은 파이썬에서는 빈 칸이 특별한 의미를 가지기 때문에 항상 일관성 있게 사용해야 한다는 뜻입니다. 이 예제에서 함수 코드는 네 칸을 띄워 썼습니다. 반드시 네 칸일 필요는 없지만 한 번 네 칸으로 들여썼다면 계속 네 칸으로 사용해야 합니다. 함수 정의를 끝내기 위해서는 들여쓰기를 하지 않으면 됩니다.
  2. 파이썬에서 if 구문 아래에는 코드 블록이 나옵니다. 만약 조건이 참이면 들여쓰기 된 블록이 실행되고, 거짓이면 else 블록을 실행하거나 else가 없을 경우 그냥 지나갑니다. if의 코드 블록에 괄호를 사용하지 않은 것을 눈여겨 보세요.
  3. 이 줄은 if 코드 블럭의 내부입니다. 만일 size < 0 이 참이면 raise 구문이 ValueError 타입의 예외를 발생시킵니다.
  4. 이 빈 라인은 함수나 if 코드 블록의 끝을 의미하지 않습니다. 완전히 빈 칸은 실제로는 무시됩니다. 단지 코드를 좀 더 읽기 쉽게 해주지요. 함수는 다음 줄로 이어집이나다.
  5. for 루프도 새로운 코드 블록의 시작을 나타냅니다. 일정한 간격으로 들여쓰기만 한다면 한 코드 블록에 여러 줄을 담아도 괜찮습니다. 이 for 루프는 세 줄의 코드를 가지고 있습니다. 여러 줄의 코드 블록이라고 해서 특별한 문법을 사용하지는 않습니다. 그냥 들여쓰기만 하세요.

처음엔 약간 어색하기도 하고 포트란을 써본 분은 좀 헷갈리기도 하겠지만, 익숙해지면 그 장점이 드러나기 시작할 겁니다. 파이썬에서 들여쓰기는 코딩 스타일이 아니라 강제적으로 따라야 하는 규칙이기 때문에, 어느 누가 작성했건 간에 코드 생김새가 비슷합니다. 그래서 다른 사람의 파이썬 코드를 읽고 이해하기가 한결 쉽습니다.

파이썬은 줄바꿈 문자(carriage return)를 사용해 문장을 나누고, 콜론과 들여쓰기로 코드 블록을 구분합니다. 반면, c++와 Java는 세미콜론을 사용해 문장을 나누고 중괄호(curly brace)로 코드 블록을 나눕니다.

예외

파이썬에서 예외는 무척 흔합니다. 거의 모든 표준 라이브러리가 예외를 사용하고, 파이썬 자체도 여러 상황에서 예외를 발생시킵니다. 이 책에서도 앞으로 계속 보게 될거예요.

그러면 예외란 무엇일까요? 일반적으로 무언가 잘못되어 오류가 발생했음을 뜻합니다. (모든 예외가 오류는 아니지만, 일단 이 부분은 신경쓰지 맙시다.) 어떤 프로그래밍 언어는 오류 처리를 위해 오류 코드를 반환하는 방식을 권장하기도 합니다. 하지만 보다 파이썬스러운 방식은 예외를 사용하고 직접 처리하는 것입니다.

파이썬 쉘에서 오류가 발생하면, 쉘은 예외에 대한 간단한 설명과 발생한 원인을 화면에 출력합니다. 그러고는 끝입니다. 그게 다죠. 이런 상황을 파이썬에서는 처리되지 않은 예외(unhandled exception)라고 부릅니다. 따로 예외를 처리할 수 있는 모듈이 없어서, 결국 파이썬 쉘이 몇 가지 디버깅 정보를 출력하고 프로그램을 끝내버릴 수밖에 없는 상황이 되는거죠. 이런 상황이 쉘 사용중에 벌어지면 별 문제가 아니겠지만, 만약 어느 서버의 데몬 프로세스로 돌고 있는 파이썬 프로그램이었다 어떨까요. 운이 좋으면 악명 높은 파란 화면만 뜨고 프로그램이 멈추고 전체 시스템이 종료될 수도 있지만, 최악의 경우엔 서버에서 하얀 연기가 모락모락 피어 오를지도 모를 일입니다. 물론 회사에 억한 심정이 있어 의도한 일일 수도 있겠지만요.

자바와는 달리, 파이썬 함수는 어떤 예외를 발생시킬 수 있는지 선언하지 않습니다. 어떤 예외를 발생시키고 처리할지는 전적으로 여러분에게 달려 있습니다.

하지만 예외가 발생했다고 해서 반드시 프로그램이 죽는 건 아닙니다. 예외를 잘 처리하면 되니까요. 어떤 경우는 코드에 실제로 버그가 있어서 예외가 발생할 수도 있습니다. (존재하지도 않는 변수에 값을 넣는 경우처럼요.) 그러나 어떤 경우에는 예외가 발생할 것을 미리 예측할 수도 있습니다. 가령, 파일을 열려고 보니 존재하지 않는다던가, import하려는 모듈이 설치되어 있지 않다거나, 데이터베이스에 연결하려는데 네트워크 문제로 연결할 수 없다거나, 보안 세션이 만료되는 등등. 이처럼 코드의 어느 부분에서 예외가 생길지를 미리 알 수 있다면, try...except 블록을 이용해서 예외처리를 하면 됩니다.

파이썬은 예외처리를 위해 try...except 블록을 사용하고, 예외를 발생시킬 때는 raise 구문을 사용합니다. 참고로, 자바와 c++에서는 예외처리 블록이 try...catch이고, 예외를 발생시킬 때는 throw 문을 사용합니다.

approximate_size() 함수는 두 가지 상황에 마주치면 예외를 발생시킵니다. 하나는 size가 처리할 수 없을만큼 큰 값을 가질 때이고, 다른 하나는 0보다 작은 값이 들어왔을 때입니다.

예외를 발생시키는 방법은 아주 간단합니다. raise 문 뒤에 예외의 이름을 쓰고, 필요하다면 디버깅을 위해 문자열 설명을 채워주면 됩니다. 문법이 함수 호출과 꽤나 비슷하죠? (실제로 예외는 클래스로 구현되어 있고, raise 구문은 ValueError 클래스의 인스턴스를 생성한 후 초기화 메소드에 'number must be non-negative' 문자열을 넘겨주는 역할을 합니다. 그런데, 우리 너무 앞서가고 있군요!)

예외처리를 꼭 예외가 발생한 함수 내에서 처리할 필요는 없습니다. 처리되지 않은 예외는 그 함수를 호출한 함수에게 돌아갑니다. 호출한 함수에서도 예외가 처리되지 않으면 다시 그 함수를 호출한 함수에게 전달되지요. 이런 식으로 계속해서 예외가 처리될 때까지 함수를 타고 올라갑니다. 만약 맨 처음 프로그램을 시작한 곳까지 올라갔는데도 예외가 처리되지 않았다면, 프로그램은 결국 비정상적으로 종료되고 파이썬은 "traceback"이라는 오류 추적 메시지를 출력합니다. 맞습니다. 이게 끝입니다. 다시 한번 말씀드리지만 프로그램이 이렇게 동작하기를 원했다면 문제는 없습니다. 여러분의 프로그램이 무엇을 하는지에 달려 있는 것이지요.

import 예외 처리하기

파이썬은 모듈 import 시 발생할 수 있는 예외처리를 위해 ImportError 라는 클래스를 정의해 두었습니다. import 예외는 다양한 상황에서 발생할 수 있지만, 대부분 import 하려는 모듈을 import 검색 경로에서 찾을 수 없을 때 발생합니다. 이런 오류를 처리하기 위해 ImportError 예외 클래스를 사용합니다. 예를 들어, chardet 라이브러리는 문자 인코딩을 자동으로 알아내는 기능을 제공하는데, 여러분의 프로그램에서 이 라이브러리를 사용하고 싶다고 해봅시다. 하지만 유저 컴퓨터에 이 라이브러리가 설치되어 있지 않더라고 프로그램을 종료하지 않고 다른 방식으로 동작시켜야 하는 상황입니다. 이럴 때 try..except 블록을 사용할 수 있습니다.

if 문으로 chardet 모듈이 존재하는지 여부도 간단히 확인할 수 있습니다:

ImportError 예외 클래스를 활용하는 다른 예는, 같은 기능을 하지만 성능은 다른(한 쪽이 더 빠르거나, 적은 메모리를 사용하거나) 두 개의 모듈을 선택적으로 import할 경우에 볼 수 있습니다. 성능이 좋은 모듈을 먼저 import 해보고, 실패하면 성능이 떨어지는 모듈을 import할 수 있겠지요. 예를 들어, XML 장에서 ElementTree라는 같은 API를 구현한 서로 다른 두 개의 모듈에 대해 이야기 합니다. 먼저 lxml이라는 서드 파티 라이브러리는 사용자가 직접 다운로드 해서 설치해야 합니다. 반면 xml.etree.ElementTree는 느리지만 파이썬 3 표준 라이브러리에 포함되어 있습니다.

코드 마지막에 xml.etree.ElementTree 모듈을 import 한 후 etree라는 별명을 주었습니다. 두 모듈 모두 공통의 api를 구현했기 때문에, 위 코드 실행 이후에는 어떤 모듈을 import 했는지 구분할 필요가 없습니다. 그리고 import한 모듈은 try 구문의 성공 여부와 관계없이 etree라는 이름으로 사용되므로, if 문을 사용해 각각의 모듈을 다른 이름으로 각각 처리해야 할 필요도 없습니다.

Unbound 변수

approximate_size() 함수에서 다음 코드를 다시 한번 살펴봅시다.

multiple이라는 변수를 미리 선언도 하지 않고 값을 할당해버렸네요. 하지만 괜찮습니다. 파이썬에서는 이렇게 할 수 있으니까요. 이런 변수를 unbound 변수라고 부릅니다. 하지만 값을 할당하지 않은 변수를 참조하는 것은 허용되지 않습니다. 이 때는 NameError 예외가 발생합니다.

별것 아닌것 처럼 보이지만, 언젠가는 이 기능에 고마워하게 될 겁니다.

대소문자 구분은 확실히

파이썬의 모든 이름은 대소문자를 구분합니다: 변수명, 함수명, 클래스명, 모듈명, 예외명. 이 모든 이름들은 대소문자를 구분합니다. 이 값들을 다룰 때는 언제나 대소문자에 유의해야 한다는 점 잊지 마세요.

스크립트 실행하기

파이썬 모듈은 객체이고 몇 가지 유용한 속성을 가지고 있습니다. 이 속성을 이용하면 여러분이 모듈을 작성하면서 동시에 테스트까지 수행할 수 있습니다. 어떻게 하냐구요? 코드 안에 조금 특별한 코드 블록을 추가하면 됩니다. 추가된 이 구문은 커맨드라인을 통해 파이썬 파일이 실행될 때 호출됩니다. humansize.py 파일의 마지막 몇 줄을 보시죠.

c 언어와 마찬가지로, 파이썬도 동일한 값인지 비교할 때 ==를 사용하고, 변수에 값을 할당할 때는 =을 사용합니다. 하지만 c 언어와 달리, 비교하는 줄과 동일한 줄에 값을 할당하는 코드까지 연달아 작성하면 파이썬은 에러를 냅니다. 이렇게 함으로써, 값을 비교하려다가 실수로 할당해 버리는 사고를 미연에 방지할 수 있습니다.

그래서 이 if 문이 대체 뭐가 그리 특별하다는 걸까요? 앞에서 말했지만, 파이썬에서는 모듈도 객체이고 모든 모듈은 __name__이라는 내장 속성을 가지고 있습니다. __name__ 속성의 값은 모듈을 쓰는 방법에 따라 다르게 설정됩니다. 만약 모듈을 import 하면 __name__에는 그 모듈의 파일이름이 들어가게 됩니다. 다만 파일의 경로와 확장자는 떼어집니다.

하지만 모듈을 하나의 독립적인 프로그램으로 실행시키는 경우도 있겠지요. 이 때는 __name____main__이라는 특별한 값이 할당됩니다. 파이썬은 위의 if 문 조건을 검사하고 식이 참이라는 것을 확인한 후(__name__ == __main__) if 구문의 내용을 실행합니다. 위의 예에서는 두 개의 값이 출력되겠네요.

자, 여기까지가 여러분의 첫번째 파이썬 프로그램입니다.

더 읽을거리


이 강의는 영어로 된 원문한글화 프로젝트를 기초로 작성되었으며, Creative Commons Attribution Share-Alike 라이센스하에 자유로운 변경, 배포가 가능합니다

7731 reads
Previous 챕터 0. 파이썬 설치하기
Next 챕터 2. 고유 자료형

Author

No discussion

Please log in to leave a comment

16.5.11618.20190612.allo
Report · Terms of Service · Privacy Policy
Lablup Inc. · Teheran-ro 145, Gangnam-gu, Seoul, Republic of Korea · 대표: 신정규 · 사업자번호: 864-88-00080 · +82 70-8200-2587

Decline Confirm

Close
Favorite Bookmark Discussion

Please copy the following address