Python 3000 또는 Py3K(Microsoft® Windows® 2000 운영 체제에서 부르는 별명)이라고도 하는 Python 버전 3은 Guido van Rossum이 개발한 범용 프로그래밍 언어의 최신 버전이다. 코어 언어의 많은 부분이 개선된 새 버전에서는 이전 버전인 2.x 제품군과의 호환성이 지원되지 않는다. 기타 변경 사항은 다음과 같다.
- 소수 나눗셈, 예를 들어 1/2이 .5를 리턴한다.
long및int유형이 하나의 유형으로 통합되었으며 후행 L이 제거되었다.True,False및None이 이제 키워드로 사용된다.
Python 3에 관한 연재 기사의 첫 번째인 이 기사에서는 새로운 print()
함수, input(), 입/출력(I/O) 변경 사항, 새로운 bytes
데이터 유형, 문자열 및 문자열 형식의 변경 사항, 마지막으로 내장 dict 유형의
변경 사항에 대해 설명한다. 이 기사는 Python에 이미 익숙하면서 긴 PEP(Python Enhancement
Proposal) 목록을 보지 않고 변경 사항을 확인하고 싶어하는 프로그래머를 대상으로 한다.
이제부터는 print가 명령문이 아닌 함수이기 때문에 더 이상
print "hello" 형식으로 입력하지 말고 print("hello")
형식으로 입력해야 한다. 물론 이를 바꾸기가 쉽지는 않을 것이다. 필자가 알고 있는 Python
프로그래머 중에 버전 3을 설치한 후 "incorrect syntax" 오류로 어려움을 겪지 않은 사람이 아무도 없었다. 추가되는 두 글자가 귀찮다는 것을 필자도 알고 있다. 더군다나 이러한 차이 때문에
이전 버전과도 호환되지 않는 것이다. 하지만 여기에는 여러 가지 장점이 있다.
표준 출력(stdout)을 로그로 리디렉션해야 하는 경우를 살펴보자. 다음
예제에서는 컨텐츠를 추가할 log.txt 파일을 열고 fid에
오브젝트를 할당한다. 그런 다음 print>>를 사용하여
문자열을 fid 파일로 리디렉션한다.
>>>fid = open("log.txt", "a")
>>>print>>fid, "log text"
|
다음은 표준 오류(sys.stderr)로 리디렉션하는 예제이다.
>>>print>>sys.stderr, "an error occurred" |
앞의 두 예제 모두 좋은 방법이지만 더욱 적합한 해결책이 있다. 새로운
구문에서는 print() 함수의 file 키워드
인수에 값을 전달하기만 하면 된다. 예를 들면, 다음과 같다.
>>>fid = open("log.txt", "a")
>>>print("log.txt", file=fid)
|
이 코드의 구문이 훨씬 더 정돈되어 있다는 것을 알 수 있다. 문자열을 sep
키워드 인수에 전달하여 분리 문자를 변경하고 다른 문자열을 end
키워드 인수에 전달하여 종료 문자열을 변경할 수 있다는 것도 또 하나의 장점이다. 다음과 같은 방법으로
분리 문자를 변경할 수 있다.
>>>print("Foo", "Bar", sep="%")
>>>Foo%Bar
|
일반적으로, 새 구문의 형식은 다음과 같다.
print([object, ...][, sep=' '][, end='endline_character_here'][, file=redirect_to_here]) |
여기서 대괄호([]) 안의 코드는 선택적이다. 기본적으로
print()만을 호출하면 줄 바꾸기 문자(\n)가
추가된다.
Python 버전 2.x에서 raw_input()은 표준
입력(sys.stdin)에 제공된 값을 읽은 후 맨 뒤에 있는 후행 줄 바꾸기 문자가 제거된 문자열을
리턴한다. 다음 예제에서는 raw_input()을 사용하여 명령
프롬프트에 제공된 문자열을 받은 후 해당 값을 quest에 할당한다.
>>>quest = raw_input("What is your quest? ")
What is your quest? To seek the holy grail.
>>>quest
'To seek the holy grail.'
|
이와는 달리 Python 2.x의 input() 함수에는 3+5와
같은 올바른 Python 표현식이 필요하다.
처음에는 input()과 raw_input()을
모두 Python 내장 네임스페이스에서 제거하는 방법이 제안되었다. 이를 위해서는 import를 사용해서 다른 입력
기능을 가져와야 한다. 이 방법에는 불합리한 면이 있다. 다음 예제를 살펴보자.
>>>quest = input("What is your quest?")
|
위 코드는 아래와 같이 변경되어야 한다.
>>>import sys
>>>print("What is your quest?")
>>>quest = sys.stdin.readline()
|
위 경우는 입력 값이 간단한 것에 비해 코드가 길고 장황하므로 초급 프로그래머에게
많은 내용을 설명해야 한다. 모듈과 import에 대한 설명이 필요하고 문자열을
인쇄하는 방법과 점(.) 연산자에 대해서도 설명해야 한다. (Java™ 언어에 비해 많은
내용이 아니라고 느낄 수도 있을 것이다.) 따라서 Python 3에서는 raw_input()의
이름이 input()으로 변경되었으며, import가 없어도 표준 입력에서
데이터를 가져올 수 있게 되었다. 버전 2.x의 input() 기능이
필요한 경우에는 동일한 결과를 리턴하는 eval(input())을 사용하면
된다.
바이너리 데이터를 저장하기 위해 새로운 데이터 유형인 바이트 리터럴과 bytes
오브젝트가 사용된다. 이 오브젝트는 0과 127 사이의 정수나 ASCII 문자만으로 이루어진 변경
불가능한 시퀀스이며 실제로 버전 2.5에 있는 bytearray 오브젝트의
변경 불가능한 버전이다. 바이트 리터럴은 해당 문자열 앞에 b가 추가된 문자열이다(예:
b'바이트 리터럴'). 바이트 리터럴을 평가하면 새 bytes 오브젝트가
생성된다. bytes() 함수를 사용하여 새 bytes
오브젝트를 만들 수 있다. bytes 오브젝트의 생성자는 다음과 같다.
bytes([initializer[, encoding]]) |
예를 들면, 다음과 같다.
>>>b = (b'\xc3\x9f\x65\x74\x61') >>>print(b) b'\xc3\x83\xc2\x9feta' |
이 예제에서는 중복된 bytes 오브젝트가 만들어진다. 왜냐하면
바이트 리터럴을 할당하는 것만으로도 bytes 오브젝트를 만들
수 있기 때문이다. (이와 같이 수행할 수는 있으나 권장하지는 않는다.) iso-8859-1 인코딩을 사용하려면 다음
방법을 시도할 수 있다.
>>>b = bytes('\xc3\x9f\x65\x74\x61', 'iso-8859-1')
>>>print(b)
b'\xc3\x83\xc2\x9feta'
|
이니셜라이저가 문자열이면 인코딩을 제공해야 한다. 이니셜라이저가 바이트 리터럴이면 인코딩 유형을 지정하지 않아도 된다. 바이트 리터럴은 문자열이 아니다. 그러나 문자열과 마찬가지로 다음과 같이 바이트를 연결할 수 있다.
>>>b'hello' b' world' b'hello world' |
bytes() 메소드를 사용하여 바이너리 데이터와
인코딩된 텍스트를 나타낼 수 있다. bytes를 str로
변환하려면 bytes 오브젝트를 디코딩해야 한다. (이에 대해서는
나중에 자세히 설명한다.) 바이너리 데이터는 decode() 메소드를
사용하여 디코딩할 수 있다. 예를 들면, 다음과 같다.
>>>b'\xc3\x9f\x65\x74\x61'.decode() 'ßeta' |
바이너리 데이터를 파일에서 직접 읽어올 수도 있다. 다음 코드를 살펴보자.
>>>data = open('dat.txt', 'rb').read()
>>>print(data) # data is a string
>>># content of data.txt printed out here
|
파일 오브젝트를 읽기 위해 바이너리 모드로 열고 전체 파일을 읽는다.
Python에는 버전 2.x 유니코드 유형과 비슷하게 작동하는 str이라는
한 가지 문자열 유형이 있다. 다시 말해서, 모든 문자열이 유니코드 문자열이다. ASCII 문자가 아닌 식별자도
사용할 수 있게 되었다. 이 점은 비라틴계 텍스트 사용자에게 매우 편리해진 부분이다. 예를 들면, 다음과 같다.
>>>césar = ["author", "consultant"] >>>print(césar) ['author', 'consultant'] |
이전 버전의 Python의 경우, repr() 메소드는 8비트 문자열을
ASCII로 변환한다. 예를 들면, 다음과 같다.
>>>repr('é')
"'\\xc3\\xa9'"
|
버전 3에서는 유니코드 문자열이 반환된다.
>>>repr('é')
"'é'"
|
앞에서 언급한 대로 유니코드 문자열은 내장 문자열 유형이다.
문자열 오브젝트와 바이트 오브젝트는 호환되지 않는다. 바이트의 문자열
표현이 필요한 경우에는 바이트 오브젝트의 decode() 메소드를
사용해야 한다. 그 반대로 문자열의 바이트 리터럴이 필요한 경우에는 문자열 오브젝트의
encode() 메소드를 사용해야 한다.
많은 Python 프로그래머들은 내장 % 연산자를 사용하여
문자열 형식을 지정하는 것이 너무 제한적이라고 느끼고 있다. 이유는 다음과 같다.
- 바이너리 연산자이기 때문에 3개 이상의 인수를 사용할 수 없다.
- 형식 문자열 인수 이외의 다른 모든 인수를 Tuple 또는 Dictionary로 줄여야 한다.
이 스타일은 유연성이 부족하기 때문에 Python 3에서는 새로운 방식으로 문자열의
형식을 지정한다. (% 연산자와 string.Template
모듈 둘 다 버전 3에 유지된다.) 문자열 오브젝트에 format() 메소드가
추가되었으며, 이 메소드는 대체 필드로 전달하는 위치 및 키워드 인수를 받는다. 대체 필드는
문자열 내에서 중괄호({})로 표시된다. 대체 필드 내의 요소는 필드라고 한다. 다음은 간단한 예제이다.
>>>"I love {0}, {1}, and {2}".format("eggs", "bacon", "sausage")
'I love eggs, bacon, and sausage'
|
{0}, {1} 및 {2} 필드는 format()
메소드에서 위치 매개변수 eggs, bacon 및
sausage를 받는다. 다음 예제에서는 format()과
전달할 키워드 인수를 사용하여 형식을 지정하는 방법을 보여 준다.
>>>"I love {a}, {b}, and {c}".format(a="eggs", b="bacon", c="sausage")
'I love eggs, bacon, and sausage'
|
다음은 위치 매개변수와 키워드 인수를 함께 사용하는 예제이다.
>>>"I love {0}, {1}, and {param}".format("eggs", "bacon", param="sausage")
'I love eggs, bacon, and sausage'
|
키워드 인수 뒤에 키워드가 아닌 인수를 사용하면 구문 오류가 발생한다는 점에 주의해야 한다. 중괄호를 이스케이프하려면 다음과 같이 이중 중괄호를 사용한다.
>>>"{{0}}".format("can't see me")
'{0}'
|
위치 매개변수 can't see me는 인쇄할 필드가 없기
때문에 인쇄되지 않는다. 이 경우에는 오류가 발생하지 않는다.
새로운 내장 함수인 format()은 단일 값의 형식을
지정한다. 예를 들면, 다음과 같다.
>>>print(format(10.0, "7.3g"))
10
|
즉, g는 너비가 고정된 숫자를 인쇄하는 일반 형식을 나타낸다. 소수점 앞의 첫 번째 숫자는 최소 너비를 지정하고 소수점 뒤의 숫자는 자릿수를 지정한다. 형식 지정자의 전체 구문은 이 기사의 범위를 벗어나는 주제이므로 여기에서는 설명하지 않는다. 그러나 참고자료 섹션에 있는 링크를 통해 자세한 정보를 확인할 수 있다.
사전에서 dict.iterkeys(), dict.itervalues() 및
dict.iteritems() 메소드가 제거된 것도 버전 3.0의 주요 변경 사항
중 하나이다. 그 대신 .keys(), .values()
및 .items()을 사용할 수 있다. 이들 메소드는 키 또는 값의 사본이 포함된 목록
대신 세트와 비슷한 형태의 경량 컨테이너 오브젝트를 리턴하도록 변경되었다. 이 방법의
장점은 키와 항목을 복사하지 않고도 키와 항목에 대해 set 연산을
수행할 수 있다는 것이다. 예를 들면, 다음과 같다.
>>>d = {1:"dead", 2:"parrot"}
>>>print(d.items())
<built-in method items of dict object at 0xb7c2468c>
|
참고: Python에서 세트는 정렬되지 않은 고유 요소의 콜렉션이다.
여기에서 필자는 두 개의 키와 값을 가지고 있는 Dictionary를 만든 후 값 목록이 아닌
오브젝트를 리턴하는 d.items()의 값을 인쇄했다. set
오브젝트와 같은 요소의 멤버십을 테스트할 수 있다.
>>>1 in d # test for membership True |
다음은 dict_values 오브젝트의 항목을 반복하는 예제이다.
>>>for values in d.items(): ... print(values) ... dead parrot |
그러나 값 목록이 실제로 필요한 경우에는 리턴된 dict
오브젝트를 언제라도 변환할 수 있다. 예를 들면, 다음과 같다.
>>>keys = list(d.keys()) >>>print(keys) [1,2] |
새로운 I/O 메커니즘을 살펴보기 전에 먼저 ABC(Abstract Base Class)를 검토해 보아야 한다. 이 연재 기사의 Part 2에서 이 주제에 대해 자세히 다룰 것이다.
ABC는 인스턴스화할 수 없는 클래스이다. ABC를 사용하려면 서브클래스에서
ABC를 상속한 후 ABC의 추상 메소드를 재정의해야 한다. @abstractmethod
데코레이터가 앞에 붙어 있지 않는 메소드는 추상 메소드이다. 새로운 ABC 프레임워크에서는 추상
속성을 정의하기 위한 @abstractproperty 데코레이터도 제공한다. 표준
라이브러리 모듈 abc를 가져와서 새 프레임워크에 액세스할 수 있다. Listing
1에서는 간단한 예제를 보여 준다.
Listing 1. 간단한 추상 기본 클래스
from abc import ABCMeta
class SimpleAbstractClass(metaclass=ABCMeta):
pass
SimpleAbstractClass.register(list)
assert isinstance([], SimpleAbstractClass)
|
register() 메소드 호출은 클래스를 인수로 받은 후
ABC를 등록된 클래스의 서브클래스로 만든다. 마지막 행에서 assert
명령문을 호출하여 이를 확인할 수 있다. Listing 2에서는 데코레이터를 사용하는 또 다른 예제를
보여 준다.
Listing 2. 데코레이터를 사용하여 구현된 추상 기본 클래스
from abc import ABCMeta, abstractmethod
class abstract(metaclass=ABCMeta):
@abstractmethod
def absMeth(self):
pass
class A(abstract):
# must implement abstract method
def absMeth(self):
return 0
|
지금까지 ABC에 대해 살펴보았다. 이제 새로운 I/O 시스템에 대해 알아보자. 이전
Python 릴리스에서는 일부 스트림 형태의 오브젝트의 경우 중요하지만 일반적이지 않은 함수(예: seek())가
없었다. 스트림 형태의 오브젝트는 read()
및 write() 메소드를 가지고 있는 파일 형태의 오브젝트이다(예: 소켓
또는 파일). Python 3에서는 스트림 형태의 오브젝트에 대해 원시 I/O 계층, 버퍼링된 I/O 계층 및
텍스트 I/O 계층과 같은 여러 가지 I/O 계층이 있으며, 이러한 각 계층은 고유 ABC와 구현을 사용하여
정의된다.
io.open(fileName))을 호출할 수도 있지만 아직까지는
내장 open(fileName) 함수를 사용하여 스트림을 연다. 이렇게 하면
버퍼링된 텍스트 파일이 리턴되며, read()와 readline()은
문자열을 리턴한다. (Python 3의 모든 문자열은 유니코드이다.) open(fileName, 'b')이라는
형식으로 버퍼링된 바이너리 파일을 열 수도 있다. 이 경우, read()는
바이트를 리턴하지만 readline()은 사용할 수 없다.
내장 open() 함수의 생성자는 다음과 같다.
open(file,mode="r",buffering=None,encoding=None,errors=None,newline=None,closefd=True) |
가능한 모드는 다음과 같다.
r: 읽기w: 쓰기 위해 열기a: 추가하기 위해 열기b: 바이너리 모드t: 텍스트 모드+: 업데이트를 위해 디스크 파일 열기U: 유니버셜 줄 바꾸기 모드
기본 모드는 rt 또는 텍스트를 읽기 위해 열기 모드로 지정된다.
buffering 키워드 인수에는 버퍼링 정책을 결정하는
다음 세 가지 정수 중 하나를 사용할 수 있다.
0: 버퍼링 해제1: 행 버퍼링> 1: 전체 버퍼링(기본값)
기본 인코딩은 플랫폼에 따라 달라진다. 파일 디스크립터 닫기 또는 closefd는
True 또는 False일 수 있다. False이면 파일을 닫은 후에도 파일 디스크립터가 유지된다. 파일
이름을 제공하는 방법이 작동하지 않는 경우에는 closefd를 True로
설정해야 한다.
open()에서 리턴하는 오브젝트는 설정된 모드에
따라 달라진다. 표 1에서는 리턴 유형을 보여 준다.
표 1. 여러 가지 열기 모드의 리턴 유형
| 모드 | 리턴된 오브젝트 |
|---|---|
| 텍스트 모드 |
TextIOWrapper
|
| 바이너리 |
BufferedReader
|
| 바이너리 쓰기 |
BufferedWriter
|
| 바이너리 추가 |
BufferedWriter
|
| 읽기/쓰기 모드 |
BufferedRandom
|
참고: 텍스트 모드는 w, r, wt, rt 등일 수 있다.
Listing 3 예제에서는 버퍼링된 바이너리 스트림을 읽기 위해 연다.
Listing 3. 버퍼링된 바이너리 스트림을 읽기 위해 열기
>>>import io
>>>f = io.open("hashlib.pyo", "rb") # open for reading in binary mode
>>>f # f is a BufferedReader object
<io.BufferedReader object at 0xb7c2534c>
>>>f.close() # close stream
|
BufferedReader 오브젝트에서는 isatty,
peek, raw, readinto,
readline, readlines, seek,
seekable, tell, writable,
write, writelines 등을 포함한 여러 가지 유용한 메소드에
액세스할 수 있다. BufferedReader 오브젝트에
대해 dir()을 실행하면 전체 목록을 볼 수 있다.
Python 커뮤니티에서 버전 3을 채택할지 여부에 대해 의문을 갖고 있는 사람도 있다. 이전 버전과의 호환성이 지원되지 않는다는 것은 서로 다른 두 버전이 동시에
지원된다는 것을 의미한다. 2to3 변환기가 있더라도 프로젝트를 마이그레이션하지 않으려는
프로젝트 개발자도 있을 것이다. Python 버전 2에서 3으로 마이그레이션하기
위해서는 일부 사항을 다시 습득해야 하는 부담이 있기는 하지만 Python에서
Java 또는 Perl 언어로 이동하는 것처럼 큰 변화는 아니다. 변경 사항 중 많은
부분은 소수 나눗셈과 dict의 변경 사항처럼 오래 전부터 예상되어
온 것이다. print()의 경우 Java의 System.out.println()에
비해 매우 쉽기 때문에 짧은 시간에 익혀서 활용할 수 있다는 장점이 있다.
필자는 많은 Python 개발자가 이전 버전과의 비호환성과 같은 일부 변경 사항이 버전 3으로 마이그레이션하는 것을 막고 있다는 블로고스피어의 글을 읽어 보았다. 람다는 원래 제거될 예정이었지만 기존 형태대로 유지되고 있다. 유지되고 있는 항목의 전체 목록은 Python core development 사이트에서 볼 수 있다. PEP 전체를 자세히 살펴보면 세부 정보를 확인할 수 있다.
이 연재 기사의 다음 기사에서는 메타클래스 구문, ABC, 데코레이터, 정수 리터럴 지원, 기본 유형 및 예외와 같은 고급 주제를 다룰 것이다.
교육
-
형식 지정자에 대한 전체 구문은 Python core development 사이트에서 볼 수 있다.
- 관련된 Python 3 PEP를 읽어보자.
- PEP 3111: Python 3000에 내장된 간단한 입력
- PEP 3116: 새로운 I/O
- PEP 3138: Python 3000의 문자열 표현
- PEP 3112: Python 3000의 바이트 리터럴
- PEP 3137: 변경 불가능한 바이트 및 변경 가능한 버퍼
- PEP 3106: dict.keys(), .values() 및 .items() 개정
- PEP 3108: 표준 라이브러리 재구성
- PEP 3100: 기타 Python 3.0 계획
- Wikipedia에서 메타클래스에 대한 설명을 읽어보자.
- Wikipedia에서 추상
클래스를 포함한 컴퓨터 클래스에 대한 설명을 살펴보자.
- Guido van Rossum의 에세이를 읽어보자.
- Python의 정렬되지
않은 고유 요소 콜렉션 또는 sets에 대한 설명을 읽어보자.
- developerWorks
Linux 영역에서는 Linux 입문자를
비롯한 Linux 개발자에게 도움이 되는 여러 가지 리소스를 제공하고 있으며
가장 인기 있는 기사와 튜토리얼도 볼 수 있다.
-
developerWorks에 있는
Linux 팁과
Linux 튜토리얼을 모두 살펴보자.
-
developerWorks
기술 행사 및 웹 캐스트를 통해 최신 정보를 얻자.
제품 및 기술 얻기
- 최신 버전의 Python을 다운로드하자.
-
developerWorks에서 직접 다운로드할 수 있는 IBM
시험판 소프트웨어를 사용하여 Linux와 관련된 후속 개발 프로젝트를 구현해 보자.
토론
-
블로그, 포럼, 포드캐스트 및 스페이스를 통해 developerWorks
커뮤니티에 참여하자.
