CodeOnWeb
로그인

부록 A. 2to3를 이용해서 코드를 파이썬 3로 이식하기

파이썬 3에 포함된 2to3 스크립트로 파이썬 2 코드를 파이썬 3로 이식할 수 있습니다.

Park Jonghyun 2015/09/01, 22:58

내용

파이썬 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. 문제 해결

"삶은 즐겁다. 죽음은 평온하다. 성가신 것은 그 둘 사이를 이동하는 과정이다."
아이작 아시모프(Isaac Asimov) (추정)

뛰어들기

파이썬 2에서 파이썬 3로 오면서 많은 것들이 변했습니다. 코드를 변경하지 않고 양 쪽 모두에서 돌아가는 프로그램은 아마 손에 꼽을 수 있을겁니다. 하지만 절망하지 마세요! 이 변화를 위해 파이썬 3는 2to3라고 불리는 스크립트를 포함하고 있습니다. 파이썬 2의 소스 코드를 입력 받아 파이썬 3로 할 수 있는 만큼 변환해 주는 자동화 도구입니다. 사례 연구: chardet을 파이썬 3로 이식하기에서 2to3 스크립트를 어떻게 실행하는지, 또 어떤 부분은 자동으로 고칠 수 없었는지 살펴보았습니다. 이 부록은 고칠 수 있는 부분에 대해 살펴보겠습니다.

print 문

파이썬 2에서 print는 구문(statement)이었습니다. 출력하고 싶은 내용이 print 키워드 뒤에 따라나왔죠. 파이썬 3에서 print()는 함수입니다. 다른 함수와 마찬가지로 출력하고 싶은 내용을 print()의 인자로 넘겨줍니다.

Notes Python 2 Python 3
#1 print print()
#2 print 1 print(1)
#3 print 1, 2 print(1, 2)
#4 print 1, 2, print(1, 2, end=' ')
#5 print >>sys.stderr, 1, 2, 3 print(1, 2, 3, file=sys.stderr)
  1. 빈 줄을 출력하면 print()를 인자 없이 호출합니다.
  2. 값 하나를 출력하려면 print() 함수에 인자 하나를 넘겨서 호출합니다.
  3. 빈 칸으로 구분해서 두 값을 출력하려면 print() 함수에 인자 두 개를 넘겨줍니다.
  4. 좀 설명이 필요한 부분입니다. 파이썬 2에서 print 문의 끝에 쉼표를 붙이면 모든 값을 빈 칸으로 구분해서 출력한 뒤, 제일 마지막 부분에 캐리지 리턴(carriage return) 대신 빈 칸 하나를 붙여주고 거기서 멈춥니다. (실제로는 이보다 좀 더 복잡합니다. 파이썬 2의 print 문은 지금은 쓰이지 않는 softspace라는 속성을 사용했습니다. 마지막 빈 칸을 실제로 출력하는 대신 sys.stdout.softspace의 값을 1로 바꾸는 것입니다. 이미 출력된 그 줄에 이어서 무언가 출력되지 않는 경우 마지막 빈 칸도 실제로는 출력되지 않습니다. 만약 다음 print문이 캐리지 리턴을 출력한다면 sys.stdout.softspace에는 0이 할당되고 마지막 빈 칸은 출력되지 않습니다. 여러분의 코드가 print가 생성한 출력의 마지막 빈 칸에 민감하게 영향받는 경우가 아니라면 눈치채기 어려웠을겁니다.) 파이썬 3에서 같은 출력을 얻으려면 end=' '라는 이름 있는 인자를 print() 함수에 던져주면 됩니다. end 인자는 기본값이 '\n'(캐리지 리턴)으로 설정되어 있으므로, 그 값을 덮어 쓰면 출력 마지막 부분에 캐리지 리턴이 출력되지 않게 됩니다.
  5. 파이썬 2에서 출력을 (sys.stderr과 같은) 파이프(pipe)로 리다이렉트(redirect)하려면 >>pipe_name 이라는 문법을 사용했습니다. 파이썬 3에서 같은 일을 하려면 file이라는 인자에 파이프를 넘겨주면 됩니다. file 인자는 기본값이 sys.stdout(표준 출력)으로 설정되어 있으므로, 이 값을 덮어 쓰면 출력이 다른 파이프로 넘어가게 됩니다.

유니코드 문자열 리터럴(literal)

파이썬 2는 유니코드 문자열과 비-유니코드(유니코드가 아닌) 문자열의 두 가지 문자열 형태를 가지고 있습니다. 파이썬 3에서 문자열은 오직 유니코드 문자열입니다.

Notes Python 2 Python 3
#1 u'PapayaWhip' 'PapayaWhip'
#2 ur'PapayaWhip\foo' r'PapayaWhip\foo'
  1. 유니코드 문자열은 문자열로 변환됩니다. 파이썬 3에서 문자열은 언제나 유니코드입니다.
  2. 유니코드 raw 문자열(파이썬이 역슬래쉬를 자동으로 escape 하지 않습니다)은 raw 문자열로 변환됩니다. 파이썬 3에서 raw 문자열은 언제나 유니코드입니다.

unicode() 전역 함수

파이썬 2는 두객체를 문자열로 강제 변환하는 두 가지 전역 함수를 가지고 있습니다. unicode()는 유니코드 문자열로 변환하고, str()은 비-유니코드 문자열로 변환합니다. 파이썬 3는 단 한 가지의 문자열(유니코드 문자열) 형태만 가지고 있습니다. 그래서 str() 함수만 있으면 됩니다. (unicode() 함수는 더 이상 존재하지 않습니다.)

Notes Python 2 Python 3
unicode(anything) str(anything)

long 데이터 형

파이썬 2는 int와 long 형을 구분했습니다. int 형의 정수는 sys.maxint에 정의된 값(플랫퐁마다 다릅니다)보다 큰 값을 가질 수 없습니다. long 형은 숫자의 끝 부분에 L을 붙여서 정의할 수 있는데, int로 표현할 수 있는 숫자보다 큰 수를 표현하기 위해 사용합니다. 파이썬 3에서는 int라는 오직 한 가지 형태의 정수만 존재하고, 파이썬 2의 long 형과 비슷하게 동작합니다. 정수가 하나로 통합되었으므로 그 둘을 구분짓는 문법은 필요하지 않습니다.

자세한 사항은 다음 문서를 참고하세요: pep 237: Unifying Long Integers and Integers (pep 237: Unifying Long Integers and Integers).

Notes Python 2 Python 3
#1 x = 1000000000000L x = 1000000000000
#2 x = 0xFFFFFFFFFFFFL x = 0xFFFFFFFFFFFF
#3 long(x) int(x)
#4 type(x) is long type(x) is int
#5 isinstance(x, long) isinstance(x, int)
  1. 10진수 long 정수는 이제 10진수 int 정수입니다.
  2. 16진수 long 정수는 이제 16진수 int 정수입니다.
  3. 파이썬 3에서는 long() 함수가 더이상 존재하지 않습니다. long 형이 없어졌으니까요. 변수를 정수형으로 강제 변환하기 위해 int() 함수를 사용합니다.
  4. 변수가 정수인지 확인하기 위해 그 변수의 형을 알아낸 뒤 long이 아니라 int와 비교합니다.
  5. 데이터의 형을 알아내기 위해 isinstance() 함수를 이용할 수도 있습니다. 마찬가지로 long 대신 int를 이용해서 정수인지 확인합니다.

<> 비교

파이썬 2는 같지 않음을 표현하는 연산자인 <>를 !=와 같이 사용할 수 있었습니다. 파이썬 3는 오직 != 연산자만 유효합니다.

Notes Python 2 Python 3
#1 if x <> y: if x != y:
#2 if x <> y <> z: if x != y != z:
  1. 단순한 비교문입니다.
  2. 세 값을 이용해 좀 더 복잡한 비교를 하고 있습니다.

has_key() 사전 메소드

파이썬 2에서 사전이 특정한 키를 가지고 있는지 확인하기 위해 has_key() 메소드를 사용할 수 있었습니다. 파이썬 3에서 이 메소드는 더이상 존재하지 않습니다. 대신 in 연산자를 사용합니다.

Notes Python 2 Python 3
#1 a_dictionary.has_key('PapayaWhip') 'PapayaWhip' in a_dictionary
#2 a_dictionary.has_key(x) or a_dictionary.has_key(y) x in a_dictionary or y in a_dictionary
#3 a_dictionary.has_key(x or y) (x or y) in a_dictionary
#4 a_dictionary.has_key(x + y) (x + y) in a_dictionary
#5 x + a_dictionary.has_key(y) x + (y in a_dictionary)
  1. 가장 간단한 형태지요.
  2. in 연산자는 or 연산자보다 우선순위가 높으므로 x in a_dictionary나 y in a_dictionary에 괄호를 씌울 필요는 없습니다.
  3. 반면 여기의 x or y에는 괄호를 씌워야 합니다. 이유는 같겠지요. in이 or보다 우선순위가 높습니다. (이 코드는 2번 코드와 완전히다 다른 코드입니다. 파이썬 해석기는 x or y를 먼저 연산해서 x(x가 참일 경우)나 y 둘 중 하나의 값을 반환합니다. 그 후 a_dictionary의 키에 이 값 하나가 있는지 확인합니다.)
    • 연산자는 in 연산자보다 우선순위가 높습니다. 그래서 사실 여기서 괄호는 필요없습니다만, 2to3는 어쨌는 추가해줍니다.
  4. 이 코드를 변환하려면 반드시 괄호를 씌워야 하겠지요. + 연산자는 in 연산자보다 우선순위가 높습니다.

리스트를 반환하는 사전 메소드

파이썬 2에서 많은 수의 사전 메소드는 리스트를 반환합니다. 가장 많이 사용되는 메소드로는 keys(), items(), values() 등이 있지요. 파이썬 3에서 이 함수들은 동적 뷰(dynamic views)(변경이 불가능한 사전 객체 기반의 반복자입니다)를 반환합니다. 어떤 상황에서는 별로 문제가 되지 않습니다. 메소드의 반환값이 바로 다른 함수로 전달되어 모든 항목을 순환하는(iterate) 경우에는 반환값이 리스트이든 뷰이든 큰 차이가 없습니다. 하지만 문제가 되는 상황도 있습니다. 리스트가 반환될 것을 예상하고 각 리스트의 개별 항목에 인덱스를 이용해서 접근하는 명령을 내렸다면, 여러분의 코드는 실행되지 않을겁니다. 뷰는 인덱싱을 지원하지 않기 때문입니다.

Notes Python 2 Python 3
#1 a_dictionary.keys() list(a_dictionary.keys())
#2 a_dictionary.items() list(a_dictionary.items())
#3 a_dictionary.iterkeys() iter(a_dictionary.keys())
#4 [i for i in a_dictionary.iterkeys()] [i for i in a_dictionary.keys()]
#5 min(a_dictionary.keys()) no change
  1. 2to3는 가능한 안전하게 변환하기 위해, keys()의 반환값을 list() 함수를 이용해 정적인 리스트로 바꾸어 버립니다. 이 변환은 언제나 문제없이 작동하지만, 뷰를 사용하는 것보다는 효율적이지 않습니다. 변환된 코드를 들여다 보고 리스트로 꼭 바꾸어야 하는지 확인한 뒤에, 그럴 필요가 없다면 list()를 제거하고 뷰를 그냥 쓰는 편이 좋습니다.
  2. items() 메소드의 반환값을 뷰에서 리스트로 바꾸는 위와 비슷한 예제입니다. 2to3는 values() 메소드에도 같은 변환을 해줍니다.
  3. 파이썬 3는 iterkeys() 메소드를 더이상 지원하지 않습니다. 대신 keys()를 사용하고 반환된 뷰를 iter() 함수를 이용해서 반복자로 바꿉니다.
  4. 2to3는 iterkeys() 메소드가 리스트 컴프리헨션 안에 사용되는 것을 인식해서 (iter()는 호출하지 않고) keys() 메소드로 바꾸어줍니다. 뷰는 반복자이기 때문에 가능한 일입니다.
  5. 2to3는 keys() 메소드의 반환값이 다른 함수로 즉시 전달되어 모든 항목을 순환하게 되는 경우에는 굳이 list()를 씌우지 않습니다. min() 함수는 인자로 받은 뷰를 아무 문제 없이 순환할 것입니다. 이는 min(), max(), sum(), list(), tuple(), set(), sorted(), any(), all() 등의 함수에도 적용됩니다.

이름이 바뀌거나 재구성된 모듈

파이썬 표준 라이브러리에 있던 몇 가지 모듈은 이름이 바뀌었습니다. 또 서로 관계가 있던 어떤 모듈은 하나로 합쳐지거나, 보다 논리적인 결합을 위해 재구성되기도 했습니다.

http

파이썬 3에서 HTTP와 관련된 몇 가지 모듈이 http라는 하나의 패키지 안으로 포함되었습니다.

Notes Python 2 Python 3
#1 import httplib import http.client
#2 import Cookie import http.cookies
#3 import cookielib import http.cookiejar
#4 import BaseHTTPServer
import SimpleHTTPServer
import CGIHttpServer
import http.server
  1. http.client 모듈은 HTTP 리소스를 요청하고 HTTP 반응을 처리하는 저수준(low-level) 라이브러리입니다.
  2. http.cookies 모듈은 Set-Cookie: HTTP 헤더로 보내진 브라우저 쿠키를 처리하는 파이썬 인터페이스를 제공합니다.
  3. http.cookiejar 모듈은 웹브라우저가 쿠키를 저장할 때 사용하는 디스크 상의 실제 파일을 다루는 라이브러리입니다.
  4. http.server 모듈은 기본적인 HTTP 서버 관련 기능을 제공합니다.

urllib

파이썬 2는 URL을 해석하고, 인코딩하고, 가져오는 기능이 서로 다른 모듈에 개미집처럼 나뉘어 있었습니다. 파이썬 3에서는 이들이 모두 urllib라는 하나의 패키지 안으로 들어왔습니다.

Notes Python 2 Python 3
#1 import urllib import urllib.request, urllib.parse, urllib.error
#2 import urllib2 import urllib.request, urllib.error
#3 import urlparse import urllib.parse
#4 import robotparser import urllib.robotparser
#5 from urllib import FancyURLopener
from urllib import urlencode
from urllib.request import FancyURLopener
from urllib.parse import urlencode
#6 from urllib2 import Request
from urllib2 import HTTPError
from urllib.request import Request
from urllib.error import HTTPError
  1. 파이썬 2의 urllib 모듈은 다양한 함수를 가지고 있습니다. 데이터를 가져오는 urlopen(), URL을 각 구성요소로 분리하기 위한 splittype(), splithost(), splituser() 등의 함수들이 있지요. 이 함수들은 새로운 urllib 패키지 내에 보다 논리적으로 재구성되었습니다. 2to3는 이 함수들을 호출하는 부분을 재구성된 이름에 맞게 모두 바꾸어 줍니다.
  2. 파이썬 2의 urllib2 모듈은 파이썬 3에서 urllib 패키지 내에 포함되었습니다. urllib2에서 자주 사용되던 build_opener() 메소드, Request 객체, HTTPBasicAuthHandler와 같은 것들은 여전히 사용할 수 있습니다.
  3. 파이썬 3의 urllib.parse 모듈은 파이썬 2의 urlparse 모듈이 포함하고 있는 모든 해석 함수를 가지고 있습니다.
  4. urllib.robotparser 모듈은 robots.txt 파일을 해석합니다.
  5. HTTP 리다이렉트와 기타 상태 코드를 처리하는 FancyUrlopener 클래스는 urllib.requset 모듈 내로 옮겨졌습니다. urlencode() 함수는 urllib.parse로 옮겨졌습니다.
  6. Request 객체는 urllib.requset로 포함된 반면, HTTPError 같은 상수는 urllib.error로 옮겨졌습니다.

2to3가 여러분의 함수 호출도 바꾼다고 말씀드렸나요? 예를 들어, 파이썬 2 코드에서 urllib 모듈을 import한 뒤 데이터를 가져오기 위해 urllib.urlopen()를 호출하는 부분이 있으면, 2to3가 import 문과 함수 호출하는 부분을 모두 바꿔줍니다.

Notes Python 2 Python 3
import urllibprint
urllib.urlopen('http://diveintopython3.org/').read()
import urllib.request, urllib.parse, urllib.error
print(urllib.request.urlopen('http://diveintopython3.org/').read())

dbm

모든 DBM 관련 모듈은 dmb이라는 하나의 패키지로 묶였습니다. GNU DBM과 같은 특정 모듈을 사용하고 싶으면 dbm 패키지 내에서 적절하게 import 하면 됩니다.

Notes Python 2 Python 3
import dbm import dbm.ndbm
import gdbm import dbm.gnu
import dbhash import dbm.bsd
import dumbdbm import dbm.dumb
import anydbmimport whichdb import dbm

xmlrpc

XML-RPC는 HTTP 상에서 원격 RPC 호출을 수행할 때 부담없이 사용할 수 있는 방법입니다. XML-RPC 클라이언트 라이브러리와 몇 가지 XML-RPC 서버 구현이 이제 xmlrpc라는 하나의 패키지로 묶였습니다.

Notes Python 2 Python 3
import xmlrpclib import xmlrpc.client
import DocXMLRPCServer
import SimpleXMLRPCServer
import xmlrpc.server

기타 모듈

Notes Python 2 Python 3
#1 try:
    import cStringIO as StringIO
except ImportError:
    import StringIO
import io
#2 try:
    import cPickle as pickle
except ImportError:
    import pickle
import pickle
#3 import __builtin__ import builtins
#4 import copy_reg import copyreg
#5 import Queue import queue
#6 import SocketServer import socketserver
#7 import ConfigParser import configparser
#8 import repr import reprlib
#9 import commands import subprocess
  1. 파이썬 2에서 cStringIO를 StringIO라는 이름으로 import 하고, 실패하면 StringIO를 대신 import 하는 방법이 흔히 사용되었습니다. 파이썬 3에서는 이렇게 하지 마세요. io 모듈이 알아서 합니다. 가능한 가장 빠른 구현 방식을 찾아서 자동으로 사용합니다.
  2. 유사하게, 가장 빠른 pickle 구현을 import하는 방법도 많이 쓰였습니다. 파이썬 3에서는 pickle 모듈이 알아서 처리하니까 그렇게 사용하지 마세요.
  3. builtins 모듈은 파이썬 언어에서 사용되는 전역 함수, 클래스, 상수를 포함하고 있습니다. builtins 모듈에 있는 함수를 재정의 하면 전역 함수를 재정의 하는 것입니다. 강력한 만큼 위험도 커지지요.
  4. copyreg 모듈은 C에 정의된 사용자 정의 형을 위한 pickle 지원을 추가했습니다.
  5. queue 모듈은 multi-producer와 multi-consumer 큐를 구현했습니다.
  6. socketserver 모듈은 서로 다른 종류의 소켓 서버를 구현하기 위한 범용 기본 클래스(generic base class)를 제공합니다.
  7. configparser 모듈은 INI 형식의 설정 파일을 해석할 수 있습니다.
  8. reprlib 모듈은 내장된 repr() 함수를 재구현했습니다. 표현이 잘리기 전에 얼마나 길 수 있는지에 대한 추가 제어를 할 수 있습니다.
  9. subprocess 모듈을 이용해 프로세스를 생성하고, 그 프로세스의 파이프(pipes)에 연결한 뒤 반환하는 코드를 얻을 수 있습니다.

패키지 내의 상대 import

패키지는 서로 관계 있는 모듈이 무리를 지어 하나로 구성된 것이라 할 수 있습니다. 파이썬 2에서 패키지 내의 모듈끼리 서로 참조할 필요가 있을 때는 import foo나 from foo import Bar와 같은 식으로 import할 수 있습니다. 파이썬 2 해석기는 foo.py를 찾기 위해 먼저 현재 패키지를 뒤져본 뒤에 파이썬 검색 경로(sys.path)에 있는 디렉토리로 이동합니다. 파이썬 3는 좀 다르게 작동합니다. 현재 패키지를 찾는 대신 바로 파이썬 검색 경로로 가버립니다. 한 패키지에 있는 모듈에서 그 패키지의 다른 모듈을 참조하려면 두 모듈 사이의 상대 경로를 명시적으로 적어줘야 합니다.

아래와 같이 같은 디렉토리에 여러 개의 파일로 구성된 패키지가 있다고 합시다.

chardet/
|
+--__init__.py
|
+--constants.py
|
+--mbcharsetprober.py
|
+--universaldetector.py

universaldetector.py에서 constants.py 파일 전체를 import 하고, mbcharsetprober.py에서는 클래스 하나면 import 하려 한다면 어떻게 해야 할까요?

Notes Python 2 Python 3
#1 import constants from . import constants
#2 from mbcharsetprober import MultiByteCharSetProber from .mbcharsetprober import MultiByteCharsetProber
  1. 패키지 내에 있는 다른 모듈 전체를 import 하려면 from . import라는 새로운 문법을 사용합니다. from 뒤의 마침표는 현재 파일(universaldetector.py)를 기준으로 import 하고자 하는 파일(constants.py)에 대한 상대 경로를 뜻합니다. 이 경우 두 파일은 같은 디렉토리에 위치하고 있으므로 마침표 하나만 찍어주면 됩니다. 물론 부모 디렉토리에 있는 파일(from .. import anothermodule)이나 하위 디렉토리에 있는 모듈도 import 할 수 있습니다.
  2. 패캐지 내의 다른 모듈에 있는 특정 클래스나 함수를 현재 모듈의 네임스페이스로 바로 import 하려면, import할 모듈 이름 앞에 상대경로(슬래시는 붙이지 않고)를 추가해주면 됩니다. 이 예제에서는 mbcharsetprober.py가 universaldetector.py와 같은 경로에 있으므로, 상대경로는 마침표 하나가 됩니다. 부모 디렉토리(from ..anothermodule import AnotherClass)나 하위 디렉토리에서 import 할 수도 있습니다.

next() 반복자 메소드

파이썬 2에서 반복자(iterator)는 다음 순서 항목을 반환해주는 next() 메소드가 있었습니다. 파이썬 3에서도 마찬가지지만, 이제는 전역 함수인 next()가 반복자를 인자로 받아서 같은 일을 수행합니다.

Notes Python 2 Python 3
#1 anIterator.next() next(anIterator)
#2 a_function_that_returns_an_iterator().next() next(a_function_that_returns_an_iterator())
#3 class A:
    def next(self):
        pass
class A:
    def __next__(self):
        pass
#4 class A:
    def next(self, x, y):
        pass
no change
#5 next = 42
for an_iterator in a_sequence_of_iterators:
    an_iterator.next()
next = 42
for an_iterator in a_sequence_of_iterators:
    an_iterator.__next__()
  1. 가장 간단한 경우로, 반복자의 next() 메소드를 호출하는 대신, 반복자 자체를 전역 next() 함수에 인자로 넘겨줍니다.
  2. 반복자를 반환하는 함수가 있다면 그 함수를 호출한 뒤 반환되는 값은 next() 함수의 인자로 넘겨줍니다. (2to3 스크립트는 이 변환을 적절하게 할 수 있을만큼 똑똑합니다.)
  3. 여러분이 직접 반복자 클래스를 정의했다면, __next__()라는 특별한 메소드를 정의합니다.
  4. 여러분이 정의한 클래스에 하나 이상의 인자를 받는 next() 메소드가 있을 겅우, 2to3는 가 메소드를 변환하지 않습니다. 이 next() 메소드가 인자른 받아들이고 있으므로, 이 클래스는 반복자로 쓰일 수 없습니다.
  5. 헷갈리기 쉬운 경우입니다. next라는 지역 변수가 있을 경우 전역 next() 함수보다 우선순위를 가지게 됩니다. 이 때 반복자의 다음 항목을 받아오려면 반복자의 특별 메소드인 __next__()를 호출해야 합니다. (코드를 좀 수정해서 next라는 이름의 지역 변수를 다른 이름으로 바꿀 수도 있지만, 2to3에서 그 일을 해주지는 않습니다.)

filter() 전역 함수

파이썬 2에서 filter() 함수는 배열의 각 항목에 함수를 적용해서 True나 False를 결정한 뒤 그 값을 리스트 형태로 반환했습니다. 파이썬 3에서 filter() 함수는 리스트 대신 반복자를 반환합니다.

Notes Python 2 Python 3
#1 filter(a_function, a_sequence) list(filter(a_function, a_sequence))
#2 list(filter(a_function, a_sequence)) no change
#3 filter(None, a_sequence) [i for i in a_sequence if i]
#4 for i in filter(None, a_sequence): no change
#5 [i for i in filter(a_function, a_sequence)] no change
  1. 가장 간단한 경우로, 2to3는 filter() 함수 호출 부분을 list() 함수로 감쌉니다. filter()에서 반환되는 반복자를 순회해서 실제 리스트를 반환하겠지요.
  2. 하지만, filter() 함수가 이미 list()로 싸여 있으면 2to3는 아무 일도 하지 않습니다. filter()가 반복자를 반환하든 리스트를 반환하든 아무 상관이 없으니까요.
  3. filter(None, ...) 문법은 같은 일을 수행하는 리스트 컴프리헨션으로 바꿔집니다.
  4. for의 조건문 등과 같이 어쨌든 모든 항목을 순회하게 되는 경우에는 따로 변경을 하지 않습니다.
  5. 여기서도 다른 변경이 필요하지 않습니다. 리스트 컴프리헨션 때문에 어차피 모든 항목을 한 번 씩 돌게 되므로, filter가 리스트나 반복자 중 무엇을 반환하더라도 결과는 같습니다.

map() 전역 함수

filter()와 마찬가지로 map() 함수도 반복자를 반환합니다. (파이썬 2에서는 리스트를 반환하지요.)

Notes Python 2 Python 3
#1 map(a_function, 'PapayaWhip') list(map(a_function, 'PapayaWhip'))
#2 map(None, 'PapayaWhip') list('PapayaWhip')
#3 map(lambda x: x+1, range(42)) [x+1 for x in range(42)]
#4 for i in map(a_function, a_sequence): no change
#5 [i for i in map(a_function, a_sequence)] no change
  1. filter()와 마찬가지로, 가장 간단한 경우 2to3는 map() 함수를 list()로 감쌉니다.
  2. map(None, ...) 문법은 리스트 컴프리헨션으로 바뀝니다.
  3. map()의 첫 번째 인자가 람다 함수(lambda function)이라면, 2to3는 그에 해당하는 리스트 컴프리헨션으로 바꿉니다.
  4. for의 조건문 등에서는 어쨌든 모든 항목을 순회하게 되므로 따로 변경할 필요가 없습니다.
  5. 여기서도 아무런 변경을 하지 않습니다. 리스트 컴프리헨션이 모든 항목을 순회하므로, map()이 리스트를 반환하든 반복자를 반환하든 상관없기 때문입니다.

reduce() 전역 함수

파이썬 3에서 reduce() 함수는 전역 네임스페이스에서 제거되고 functools 모듈 아래에 포함되었습니다.

Notes Python 2 Python 3
reduce(a, b, c) from functools import reduce
reduce(a, b, c)

apply() 전역 함수

파이썬 2는 apply()라는 전역함수를 가지고 있는데, 함수 f와 리스트 [a, b, c]를 인자로 받아 f(a, b, c)를 반환합니다. 리스트 앞에 별표(*)를 붙인 채로 함수의 인자로 넘겨주면 똑같은 일을 할 수 있습니다. 파이썬 3에서 apply() 함수는 더이상 존재하지 않으므로, 별표를 이용한 문법을 사용해야 합니다.

Notes Python 2 Python 3
#1 apply(a_function, a_list_of_args) a_function(*a_list_of_args)
#2 apply(a_function, a_list_of_args,a_dictionary_of_named_args) a_function(a_list_of_args,*a_dictionary_of_named_args)
#3 apply(a_function, a_list_of_args + z) a_function(*a_list_of_args + z)
#4 apply(aModule.a_function, a_list_of_args) aModule.a_function(*a_list_of_args)
  1. 가장 간단한 형태로, 별표(*)를 리스트 앞에 붙여 리스트 항목을 개별 인자로 바꿔 함수에 전달할 수 있습니다. 파이썬 2에서 apply() 함수를 사용하는 것과 동일한 결과를 줍니다.
  2. 파이썬 2에서 apply() 함수는 사실 세 개의 인자를 받을 수 있습니다. 함수, 인자 리스트, 그리고 이름 있는 인자를 담은 사전입니다. 파이썬 3에서는 리스트에 별표 하나()를 붙이고, 이름 있는 인자 사전에는 별 두 개(*)를 붙여서 같은 일을 할 수 있습니다.
  3. 리스트를 합치기 위해 사용하는 + 연산자는 * 연산자보다 우선순위가 높습니다. 그래서 a_list_of_args + z에 괄호를 굳이 추가할 필요는 없습니다.
  4. 2to3 스크립트는 import된 모듈 내의 함수를 호출하는 복잡한 apply() 함수도 제대로 변환해줍니다.

intern() 전역 함수

파이썬 2에서는 intern() 함수를 통해 문자열을 등록해서 성능 향상을 꾀할 수 있습니다. 파이썬 3에서 intern() 함수는 sys 모듈로 옮겨졌습니다.

Notes Python 2 Python 3
intern(aString) sys.intern(aString)

exec 문

print 문이 파이썬 3에서는 함수로 바뀐 것처럼, exec 문도 함수로 바뀌었습니다. exec() 함수는 임의의 파이썬 코드를 담은 문자열을 인자로 받아 그 코드를 실행합니다. exec()는 eval()과 비슷하지만 더 강력하고 더 위험합니다. eavl() 함수는 오직 하나의 표현만 평가할 수 있습니다. 하지만 exec()는 여러 구문을 실행할 수 있고, import도 가능하며, 함수를 선언할 수도 있는 등, 사실상 파이썬의 거의 모든 기능을 실행할 수 있습니다.

Notes Python 2 Python 3
#1 exec codeString exec(codeString)
#2 exec codeString in a_global_namespace exec(codeString, a_global_namespace)
#3 exec codeString in a_global_namespace,a_local_namespace exec(codeString, a_global_namespace, a_local_namespace)
  1. 가장 간단한 형태인데, 2to3 스크립트는 문자열로 된 코드를 괄호로 감싸줍니다. 파이썬 3에서는 exec()가 함수이기 때문이죠.
  2. 파이썬 2의 exec 문에 문자열로 된 코드가 실행할 때 지정되는 전역 네임스페이스를 설정할 수 있습니다. 파이썬 3에서는 전역 네임스페이스를 exec() 함수의 두 번째 인자로 던져주면 같은 일을 할 수 있습니다.
  3. 파이썬 2의 exec 문에 지역 네임스페이스도 설정할 수 있는 것처럼(함수 내에 정의된 변수를 생각하시면 됩니다), 파이썬 3의 exec() 함수도 세 번째 인자로 넘겨서 설정할 수 있습니다.

execfile 문

파이썬 2의 exec 문과 마찬가지로, execfile 문은 문자열을 마치 파이썬 코드인 것처럼 실행합니다. exec가 문자열을 인자로 받았다면, execfile은 파일 이름을 인자로 받습니다. 파이썬 3에서 execfile 문은 없어졌습니다. 파일로 된 파이썬 코드를 정말 실행하고 싶다면(하지만 import 하기는 싫다면), 파일을 열고, 그 내용을 읽어서, 전역 compile() 함수를 호출해 파이썬 해석기가 코드를 컴파일 하게 한 후, exec() 함수를 호출할 수 있습니다.

Notes Python 2 Python 3
execfile('a_filename') exec(compile(open('a_filename').read(), 'a_filename','exec'))

repr 리터럴(`)

파이썬 2에서 객체의 양쪽을 역따옴표(`)로 감싸서 그 객체의 표현식(representation of the object)을 얻는 문법이 있었습니다. 파이썬 3에서 이 기능 자체는 여전히 존재하지만 역따옴표 문법은 사라졌습니다. 대신 repr() 함수를 이용할 수 있습니다.

Notes Python 2 Python 3
#1 `x` repr(x)
#2 `'PapayaWhip' + `2`` repr('PapayaWhip' + repr(2))
  1. x는 어떤 것이라도 될 수 있습니다. 클래스, 함수, 모듈, 기본 데이터형 등 모든 것이요. repr() 함수는 모든 것에 적용할 수 있습니다.
  2. 파이썬 2에서는 역따옴표 내에 또 다른 역따옴표를 겹쳐 쓸 수 있어서 (유효하긴 하지만) 좀 헷갈리는 표현이 나오기도 합니다. 2to3는 이 표현을 repr() 내에 repr()을 겹쳐 쓰는 방식으로 잘 바꿔줍니다.

try...except 문

파이썬 2에서 3로 오면서 예외를 잡아내는 문법도 약간 바뀌었습니다.

Notes Python 2 Python 3
#1 try:2
    import mymodule
except ImportError, e
    pass
try:
    import mymodule
except ImportError as e:
    pass
#2 try:
    import mymodule
except (RuntimeError, ImportError), e
    pass
try:
    import mymodule
except (RuntimeError, ImportError) as e:
    pass
#3 try:
    import mymodule
except ImportError:
    pass
no change
#4 try:
    import mymodule
except:
    pass
no change
  1. 예외 형태에 쉼표를 사용하는 대신, 파이썬 3에서는 새로운 키워드인 as를 사용합니다.
  2. as 키워드는 여러 예외를 한 번에 처리할 때도 사용할 수 있습니다.
  3. 예외를 잡기는 하지만 예외 객체 자체를 다룰 필요는 없다면, 파이썬 2와 파이썬 3의 문법은 같습니다.
  4. 비슷하게, 모든 예외를 다 잡으려고 한다면 문법에 변화가 없습니다.

모듈을 import할 때(사실 그 외 대부분의 경우에도) 모든 예외를 한 번에 잡는 것은 좋은 생각이 아닙니다. 그럴 경우 KeyboardInterrupt(프로그램을 종료하기 위해 Ctrl-C를 누를 때 발생)와 같은 오류도 모두 잡게 되어 디버그 하기 상당히 까다로워 집니다.

raise 문

파이썬 2에서 파이썬 3로 오면서 예외를 발생시기는 문법도 조금 바뀌었습니다.

Notes Python 2 Python 3
#1 raise MyException unchanged
#2 raise MyException, 'error message' raise MyException('error message')
#3 raise MyException, 'error message', a_traceback raise MyException('error message').with_traceback(a_traceback)
#4 raise 'error message' unsupported
  1. 별다른 오류 메시지 없이 예외를 발생시킬 때는 문법의 변화가 없습니다.
  2. 여러분의 오류 메시지를 포함해서 예외를 발생시키려고 하면 문법을 좀 바꿔줘야 합니다. 파이썬 2는 예외 클래스와 메시지를 쉼표로 구분하지만, 파이썬 3에서는 오류 메시지를 인자로 전달합니다.
  3. 파이썬 2는 tracback까지 포함해서 예외를 발생시키는 조금 더 복잡한 문법을 지원합니다. 파이썬 3에서는 같은 일을 하려면 문법이 많이 바뀝니다.
  4. 파이썬 2에서는 예외 클래스 없이 오류 메시지만 가지고 오류를 발생시킬 수 있었습니다. 파이썬 3에서 이런 일은 더이상 할 수 없습니다. 2to3는 이 문제를 자동으로 해결하지 못했다고 경고할 것입니다.

제너레이터의 throw 메소드

파이썬 2에서 제너레이터는 throw() 메소드를 가지고 있습니다. a_generator.throw()를 호출하면 제너레이터가 멈춘 부분에서 예외를 발생시키고, 제너레이터 함수가 yield하는 다음 값을 반환합니다. 파이썬 3에서도 이 기능은 여전히 존재하지만 문법이 좀 바뀌었습니다.

Notes Python 2 Python 3
#1 a_generator.throw(MyException) no change
#2 a_generator.throw(MyException, 'error message') a_generator.throw(MyException('error message'))
#3 a_generator.throw('error message') unsupported
  1. 가장 간단한 형태로, 제너레이터가 별도의 오류 메시지 없이 예외를 발생시킵니다. 이 경우에는 문법이 변하지 않습니다.
  2. 제너레이터가 오류 메시지와 함께 예외를 발생시킵니다. 파이썬 3에서는 오류 메시지가 담긴 문자열을 생성하려는 예외의 인자로 넘겨줘야 합니다.
  3. 파이썬 2에서는 오류 메시지만 가지고 예외를 발생시킬 수 있습니다. 파이썬 3에서는 그렇게 할 수 없고, 2to3 스크립트는 이 코드를 수동으로 변경해야 한다는 경고를 띄웁니다.

xrange() 전역 함수

파이썬 2에서 어떤 범위의 숫자를 얻는 두 가지 방법이 있습니다. range()는 리스트를 반환하고, xrange()는 반복자를 반환합니다. 파이썬 3에서 range()는 반복자를 반환하고, xrange()는 존재하지 않습니다.

Notes Python 2 Python 3
#1 xrange(10) range(10)
#2 a_list = range(10) a_list = list(range(10))
#3 [i for i in xrange(10)] [i for i in range(10)]
#4 for i in range(10): no change
#5 sum(range(10)) no change
  1. 가장 간단한 형태로, 2to3 스크립트는 xrange()를 그냥 range()로 바꿉니다.
  2. 파이썬 2 코드에서 range()를 사용한다면, 2to3 스크립트는 이 코드에 리스트가 꼭 필요한지 반복자로도 괜찮은지 판단하지 못합니다. 그래서 일단 안전하게 list() 함수로 감싸서 리스트를 반환하게 바꿉니다.럼
  3. xrange() 함수가 리스트 컴프리헨션 안에 있다면, 2to3 스크립트는 range() 함수에 list()를 덧씌우지 않습니다. 리스트 컴프리헨션은 range() 함수에서 반복자가 돌아와도 잘 작동하기 때문입니다.
  4. 비슷하게, for 문에 반복자가 반환되어도 문제가 없습니다. 그래서 바꿀 필요가 없지요.
  5. sum() 함수도 반복자를 인자로 받아 작동할 수 있기에, 2to3는 아무 변화를 주지 않습니다. 리스트 대신 뷰를 반환하는 사전 메소드에서 본 것처럼, 이는 min(), max(), list(), tuple(), set(), sorted(), any(), all() 등의 함수에도 적용됩니다.

raw_input()과 input() 전역 함수

파이썬 2는 커맨드 라인에서 사용자의 입력을 받는 두 가지 전역 함수를 가지고 있습니다. 하나는 input()으로 사용자가 파이썬 표현식을 입력하기를 기대하고, 입력된 표현식을 평가해서 돌려줍니다. 다른 하나는 raw_input()으로 사용자가 입력한 내용 그대로를 반환합니다. 이런 구분은 초보자에게 혼란을 주엇고, 대체로 언어의 "사마귀"라는 평가를 받아왔습니다. 파이썬 3에서는 이 사마귀를 제거하고 raw_input()을 input()으로 바꾸어, 모든 사람이 자연스럽게 예상할 수 있는 방식으로 동작하게 바꾸었습니다.

Notes Python 2 Python 3
#1 raw_input() input()
#2 raw_input('prompt') input('prompt')
#3 input() eval(input())
  1. 가장 간단한 형태로 raw_input()은 input()으로 바뀝니다.
  2. 파이썬 2에서 raw_input() 함수에 도움 메시지를 인자로 넘길 수 있습니다. 이는 파이썬 3에서도 유지되고 있습니다.
  3. 사용자가 평가할 수 있는 파이썬 표현식을 입력하길 원한다면, input() 함수의 반환값을 eval()에 명시적으로 넘겨줘야 합니다.

func_* 함수 속성

파이썬 2에서 한 함수의 특별한 속성에 접근하는 방법이 있습니다. 파이썬 3에서는 이 속성의 이름이 다른 속성과의 일관성을 유지하기 위해 바뀌었습니다.

Notes Python 2 Python 3
#1 a_function.func_name a_function.__name__
#2 a_function.func_doc a_function.__doc__
#3 a_function.func_defaults a_function.__defaults__
#4 a_function.func_dict a_function.__dict__
#5 a_function.func_closure a_function.__closure__
#6 a_function.func_globals a_function.__globals__
#7 a_function.func_code a_function.__code__
  1. __name__ 속성(이전에는 func_name)은 함수의 이름을 가지고 있습니다.
  2. __doc__ 속성(이전에는 func_doc)은 함수의 소스 코드에 정의된 docstring을 가지고 있습니다.
  3. __defaults__ 속성(이전에는 func_defaults)은 함수에 기본 인자(default argument)가 있을 경우 그 값을 담고 있는 튜플입니다.
  4. __dict__ 속성(이전에는 func_dict)은 임의의 함수 속성을 지원하는 네임스페이스입니다.
  5. __closure__ 속성(이전에는 func_closure)은 함수의 자유 변수(free variables)와의 결합(bindings)을 포함하는 셀의 튜플(tuple of cells)입니다.
  6. __globals__ 속성(이전에는 func_globals)은 함수가 정의된 모듈의 전역 네임스페이스에 대한 참조입니다.
  7. __code__ 속성(이전에는 func_code)은 함수 내용을 컴파일한 코드 객체입니다.

xreadlines() I/O 메소드

파이썬 2에서 파일 객체는 xreadlines() 메소드를 가지고 있습니다. 이 메소드는 파일을 한 줄씩 읽어들일 수 있는 반복자를 반환하는데, for 문에서 유용하게 쓸 수 있는 표현입니다. 사실 너무 유용해서 파이썬 2의 후기 버전에서는 그 기능을 파일 객체 자체에 추가해버렸습니다.

파이썬 3에서 xreadlines() 메소드는 더이상 존재하지 않습니다. 2to3가 간단한 경우는 변환해주지만, 그렇지 못한 경우는 수동으로 변환해야 합니다.

Notes Python 2 Python 3
#1 for line in a_file.xreadlines(): for line in a_file:
#2 for line in a_file.xreadlines(5): no change (broken)
  1. xreadlines() 메소드를 인자 없이 호출했다면, 2to3가 xreadlines()를 없애고 파일 객체로 대체해줍니다. 파이썬 3에서는 이런 식으로 쓸 수 있습니다. 파일을 한 번에 한 줄씩 읽고 for 문의 내용을 실행합니다.
  2. xreadlines()에 인자(한 번에 읽어들일 줄의 수)를 넘겨준 경우에는 2to3가 따로 고치지 않으므로, 여러분의 코드는 AttributeError: '_io.TextIOWrapper' object has no attribute 'xreadlines'와 같은 오류를 발생하고 실행되지 않을겁니다. 여러분이 직접 xreadlines()를 readlines()로 바꿔서 파이썬 3에서 작동하게 만들 수 있습니다. (readlines() 메소드는 반복자를 반환하므로 파이썬 2의 xreadline() 만큼이나 효율적입니다.)

여러 개의 인자 대신 튜플을 받는 lambda 함수

파이썬 2에서 일정한 개수의 항목을 가지는 튜플을 인자로 받는 이름 없는 labmda 함수를 정의할 수 있습니다. 파이썬 2는 이 튜플을 "풀어서" 이름 있는 인자로 변환하므로, lambda 함수 내에서 그 변수들을 이름으로 참조할 수 있습니다. 파이썬 3에서도 lambda 함수에 튜플을 전달할 수 있지만, 파이썬 해석기가 튜플을 이름 있는 인자로 풀어주지는 않습니다. 대신 각 인자를 위치 인덱스(positional index)로 참조해야 합니다.

Notes Python 2 Python 3
#1 lambda (x,): x + f(x) lambda x1: x1[0] + f(x1[0])
#2 lambda (x, y): x + f(y) lambda x_y: x_y[0] + f(x_y[1])
#3 lambda (x, (y, z)): x + y + z lambda x_y_z: x_y_z[0] + x_y_z[1][0] + x_y_z[1][1]
#4 lambda x, y, z: x + y + z unchanged
  1. 항목이 하나인 튜플을 인자로 받는 lambda 함수를 정의했다면, 파이썬 3에서 그 인자는 x1[0]으로 접근할 수 있습니다. x1이라는 이름은 파이썬 2 코드의 이름 있는 인자를 기반으로 2to3에 의해 자동 생성됩니다.
  2. 항목이 두 개인 튜플 (x, y)을 인자로 받는 lambda 함수는 두 개의 위치 인자(positional arguments) x_y[0]과 x_y[1]을 가지는 x_y로 변환됩니다.
  3. 2to3 스크립트는 이름 있는 인자의 튜플이 중첩되어 있는 lambda 함수도 처리할 수 있습니다. 변환된 파이썬 3 코드가 좀 알아보기는 힘들지만 파이썬 2에서 작동하던 그 방식과 같이 작동합니다.
  4. 여러 개의 항목을 따로 받는 lambda 함수를 정의할 수도 있습니다. 인자 주위에 괄호가 없으면 파이썬 2는 여러 인자를 가지는 lambda 함수로 취급합니다. 다른 일반적인 함수와 마찬가지로, lambda 함수 내에서 인자를 각각의 이름으로 접근할 수 있습니다. 이문법은 파이썬 3에서도 잘 작동합니다.

특수 메소드 속성

파이썬 2에서 클래스 메소드는 메소드 객체 뿐만 아니라 그 메소드가 정의되어 있는 클래스 객체를 참조할 수 있습니다. im_self는 클래스 개체이고, im_func는 함수 객체이며, im_class는 im_self의 클래스입니다. 파이썬 3에서 이 특수 메소드 속성은 다른 속성의 이름과 일관성을 유지하기 위해 좀 변경되었습니다.

Notes Python 2 Python 3
aClassInstance.aClassMethod.im_func aClassInstance.aClassMethod.__func__
aClassInstance.aClassMethod.im_self aClassInstance.aClassMethod.__self__
aClassInstance.aClassMethod.im_class aClassInstance.aClassMethod.__self__.__class__

__nonzero__ 특수 함수

파이썬 2에서 boolean context에 사용할 수 있는 여러분의 클래스를 생성할 수 있습니다. 예를 들어, 그 클래스를 개체화 한 뒤 if 문의 조건에 사용할 수 있는데, 그렇게 하기 위해서는 True나 False를 반환하는 __nonzero__()라는 특수한 메소드를 정의해야 합니다. 이 메소드는 개체가 boolean context에서 사용되면 호출됩니다. 파이썬 3에서 이 메소드의 이름은 __bool__()로 바뀌었습니다.

Notes Python 2 Python 3
#1 class A:
    def __nonzero__(self):
        pass
class A:
    def __bool__(self):
        pass
#2 class A:
    def __nonzero__(self, x, y):
        pass
no change
  1. 개체가 boolean context에 사용되면, 파이썬 3에서는 __nonzero__() 대신 __bool__() 메소드를 호출합니다.
  2. 하지만 인자를 받아들이는 __nonzero__() 함수가 있으면, 2to3는 이 메소드가 다른 목적으로 사용된다고 가정하고 따로 변경하지 않습니다.

8진수 리터럴

8진수(octal) 숫자를 정의하는 방식이 조금 바뀌었습니다.

Notes Python 2 Python 3
x = 0755 x = 0o755

sys.maxint

long과 int 형이 합쳐지면서 sys.maxint 상수는 더이상 정확하지 않습니다. 플랫폼에 따라 필요한 경우도 있을 수 있기에 제거되지는 않았지만, 이름은 sys.maxsize로 바뀌었습니다.

Notes Python 2 Python 3
#1 from sys import maxint from sys import maxsize
#2 a_function(sys.maxint) a_function(sys.maxsize)

callable() 전역 함수

파이썬 2에서 객체가 (함수처럼) 호출 가능한지 확인할 수 있는 전역 함수 callable()이 있습니다. 파이썬 3에서 이 전역 함수는 삭제되었습니다. 객체가 호출 가능한지 확인하려면 __call__()이라는 특수 메소드가 있는지 확인하세요.

Notes Python 2 Python 3
callable(anything) hasattr(anything, '__call__')

zip() 전역 함수

파이썬 2에서 전역 함수 zip()은 임의의 개수의 서열(sequence)을 인자로 받아서 튜플의 리스트를 반환합니다. 첫 번째 튜플은 각 서열의 첫 번째 항목을 포함하고, 두 번째 튜플은 각 항목의 두 번째 항목을 포함하는 식입니다. 파이썬 3에서 zip()은 리스트 대신 반복자를 반환합니다.

Notes Python 2 Python 3
#1 zip(a, b, c) list(zip(a, b, c))
#2 d.join(zip(a, b, c)) no change
  1. 가장 단순한 형태로, zip()이 반환하는 반복자를 list() 함수로 감싸서 반복자를 순환한 뒤 리스트를 반환하게 합니다.
  2. 서열의 모든 항목을 순환하는 경우에는 (여기의 join() 메소드를 호출하는 것처럼), zip()이 반환하는 반복자를 굳이 바꿀 필요가 없습니다. 2to3 스크립트는 이런 경우를 잘 확인해서 코드를 변경하지 않습니다.

StandardError 예외

파이썬 2에서 StandardError는 StopIteration, GeneratorExit, KeyboardInterrupt, SystemExit을 제외한 모든 내장 예외의 부모 클래스입니다. 파이썬 3에서 StandardError는 삭제되었고 대신 Exception을 사용합니다.

Notes Python 2 Python 3
x = StandardError() x = Exception()
x = StandardError(a, b, c) x = Exception(a, b, c)

types 모듈 상수

types 모듈은 객체의 형을 결정하는 데 도움을 주는 다양한 상수를 포함하고 있습니다. 파이썬 2에서는 types가 dict나 int와 같은 모든 기본 형에 대한 상수를 포함합니다. 파이썬 3에서 이 상수들은 삭제되었고, 대신 각 형의 이름을 사용하게 됩니다.

Notes Python 2 Python 3
types.UnicodeType str
types.StringType bytes
types.DictType dict
types.IntType int
types.LongType int
types.ListType list
types.NoneType type(None)
types.BooleanType bool
types.BufferType memoryview
types.ClassType type
types.ComplexType complex
types.EllipsisType type(Ellipsis)
types.FloatType float
types.ObjectType object
types.NotImplementedType type(NotImplemented)
types.SliceType slice
types.TupleType tuple
types.TypeType type
types.XRangeType range

types.StringType은 str이 아니라 bytes와 대응되는데, 파이썬 2에서 "문자열"(유니코드 문자열이 아닌 일반 문자열)은 특정 문자 인코딩을 가지는 바이트 배열이기 때문입니다.

isinstance() 전역 함수

isinstance() 함수는 한 객체가 특정 클래스나 형(type)의 개체(instance)인지 확인할 때 사용합니다. 파이썬 2에서 형을 항목으로 가지는 튜플을 isinstance()에 넘겨주면, 객체가 튜플에 담긴 형 중에서 어느 하나에 해당되면 True를 반환합니다. 파이썬 3에서도 같은 일을 할 수 있지만, 같은 형을 두 번 넘겨줄 필요는 없습니다.

Notes Python 2 Python 3
isinstance(x, (int, float, int)) isinstance(x, (int, float))

basestring 데이터형

파이썬 2는 유니코드와 비(non)-유니코드의 두 가지 문자열 형태를 가지고 있습니다. 그런데 basestring이라는 다른 형도 하나 있습니다. str과 unicode 형의 수퍼클래스(superclass)로 추상화된 형이라고 할 수 있습니다. 직접 호출하거나 개체화할 수는 없지만, 전역 함수인 isinstance()에 인자로 넘겨서 객체가 유니코드나 비(non)-유니코드 중 하나에 해당하는지 확인하는 데 사용할 수 있습니다. 파이썬 3에서는 오직 한 가지 문자열 형태만 존재하므로 basestring이 있을 이유가 없습니다.

Notes Python 2 Python 3
isinstance(x, basestring) isinstance(x, str)

itertools 모듈

itertools 모듈은 파이썬 2.3에서 등장했는데, 전역 함수인 zip(), map(), filter() 함수의 변종으로 리스트 대신 반복자를 반환합니다. 파이썬 3에서는 전역 함수가 반복자를 반환하므로 itertools 모듈에 있는 함수는 삭제되었습니다. (하지만 이 이외에 여러 가지 유용한 함수가 itertools 모듈에 있습니다.)

Notes Python 2 Python 3
#1 itertools.izip(a, b) zip(a, b)
#2 itertools.imap(a, b) map(a, b)
#3 itertools.ifilter(a, b) filter(a, b)
#4 from itertools import imap, izip, foo from itertools import foo
  1. itertools.izip() 대신 그냥 전역 함수인 zip()을 사용합니다.
  2. itertools.imap() 대신 map()을 사용합니다.
  3. itertools.ifilter()는 filter()로 변환됩니다.
  4. itertools 모듈은 파이썬 3에서도 여전히 존재합니다. 다만 전역 함수로 기능이 이전된 함수만 제거되었을 뿐입니다. 2to3 스크립트는 이제 존재하지 않는 함수에 대한 import만 제거하고 나머지는 그대로 둡니다.

sys.exc_type, sys.exc_value, sys.exc_traceback

파이썬 2는 예외가 처리되는 동안 접근할 수 있는 세 가지 변수(sys.exc_type, sys.exc_value, sys.exc_traceback)를 sys 모듈에 정의하고 있습니다. (사실, 이들 변수의 기원은 파이썬 1까지 올라갑니다.) 파이썬 1.5 이후로 이 세 변수의 값을 항목으로 하는 튜플을 반환하는 sys.exc_info()의 존재로 인해 쓰이지 않게 되었습니다. 파이썬 3에서 이 세 가지 개별 변수가 마침내 제거되었습니다. sys.exc_info() 함수를 사용하세요.

Notes Python 2 Python 3
sys.exc_type sys.exc_info()[0]
sys.exc_value sys.exc_info()[1]
sys.exc_traceback sys.exc_info()[2]

튜플에 대한 리스트 컴프리헨션

파이썬 2에서 튜플을 순환하는 리스트 컴프리헨션을 사용할 때, 튜플의 값에 괄호를 추가할 필요가 없었습니다. 파이썬 3에서는 명시적으로 괄호를 추가해줘야 합니다.

Notes Python 2 Python 3
[i for i in 1, 2] [i for i in (1, 2)]

os.getcwdu() 함수

파이썬 2에는 현재 작업 디렉토리를 (비-유니코드) 문자열로 반환하는 os.getcwd()라는 함수가 있습니다. 현대적인 파일 시스템은 디렉토리 이름에 어떤 문자 인코딩을 사용해도 다룰 수 있으므로, 파이썬 2.3에서 os.getcwdu()를 소개했습니다. os.getcwdu() 함수는 현재 작업 디렉토리를 유니코드 문자열 형태로 반환합니다. 파이썬 3에서는 오직 한 종류의 문자열(유니코드)만 존재하므로 os.getcwd()만 있으면 됩니다.

Notes Python 2 Python 3
os.getcwdu() os.getcwd()

메타 클래스(Metaclasses)

파이썬 2에서 클래서 선언할 때 metaclass 인자를 넘기거나 특수 클래스 속성인 __metaclass__를 정의함으로써 메타 클래스(metaclass)를 생성할 수 있습니다. 파이썬 3에서는 클래스 속성이 제거되었습니다.

Notes Python 2 Python 3
#1 class C(metaclass=PapayaMeta):
    pass
unchanged
#2 class Whip:
    __metaclass__ = PapayaMeta
class Whip(metaclass=PapayaMeta):
    pass
#3 class C(Whipper, Beater):
    __metaclass__ = PapayaMeta
class C(Whipper, Beater, metaclass=PapayaMeta):
    pass
  1. 클래스를 선언할 때 메타 클래스를 생성하는 것은 파이썬 2와 파이썬 3에서 모두 작동합니다.
  2. 클래스 속성을 이용해서 메타 클래스를 생성하는 것은 파이썬 2에서만 작동합니다.
  3. 2to3 스크립트는 파이썬 3를 위해 유효한 메타 클래스 생성 코드로 바꾸어 줍니다. 클래스가 하나 이상의 부모 클래스를 가질 때에도 문제 없습니다.

스타일의 문제

이제부터 등장하는 "변경" 사항은 실제로 변경된 부분은 아닙니다. 즉, 구현 방식 자체가 바뀐 것이 아니라 사용 스타일을 바꾼 것입니다. 파이썬 2에서 쓰던 방식이 파이썬 3에서도 잘 작동하지만, 파이썬 개발자는 파이썬 코드를 가능한 일정한 형식으로 만드는 데 관심이 많습니다. 그래서 파이썬 공식 스타일 가이드라는 문서를 만들어 모든 종류의 코딩 스타일에 대해 지나칠 정도로 자세하게 서술해두고 있기도 합니다. 대부분의 사람은 별로 신경쓰지 않겠지만요. 그래서 2to3는 파이썬 코드를 변환하는 방대한 기반 기능을 제공하는 것에 더해, 몇 가지 파이썬 프로그램의 가독성을 높이기 위한 추가 기능도 함께 제공합니다.

set() 리터럴(명시적)

파이썬 2 코드에서 집합을 정의하는 유일한 방법은 set(a_sequence)를 호출하는 것입니다. 파이썬 3에서도 이 방법이 통하지만 더 명확한 정의하기 위해 중괄호를 이용한 방법도 추가되었습니다. 빈 집합을 정의하는 경우를 제외하면 모든 집합에서 사용할 수 있습니다. 빈 집합 정의가 제외되는 이유는, {}가 빈 사전을 정의하는 데 쓰이기 때문입니다. 즉, {}는 빈 사전이고 빈 집합이 아닙니다.

2to3 스크립트는 기본적으로 set() 리터럴을 수정하지 않습니다. 수정하고 싶으면 2to3를 호출할 때 명령행 인자로 -f set_literal을 지정하십시오.

Notes Before After
set([1, 2, 3])
set((1, 2, 3))
set([i for i in a_sequence])

buffer() 전역 함수(명시적)

C로 구현된 파이썬 객체는 다른 파이썬 코드에서 메모리 블록을 직접 읽고 쓸 수 있는 "버퍼 인터페이스(buffer interface)"라는 것을 내보낼(export) 수 있습니다. (아주 강력한 기능임과 동시에 위험한 기능이기도 합니다.) 파이썬 3에서 buffer()는 memoryview()로 이름이 바뀌었습니다. (사실 단순히 이름이 바뀐 것보다는 더 복잡한 내용이 있지만, 대부분의 경우 그 차이를 신경쓸 필요는 없습니다.)

2to3 스크립트는 기본적으로 buffer() 함수를 수정하지 않습니다. 수정하고 싶으면 2to3를 호출할 때 명령행 인자로 -f buffer를 지정하십시오.

Notes Before After
x = buffer(y) x = memoryview(y)

쉼표 주위의 공백(명시적)

파이썬은 코드 블록 설정을 위한 들여쓰기와 내어쓰기에는 아주 엄격하지만, 다른 부분에서는 공백의 사용에 별 제한을 두지 않는 편입니다. 리스트, 튜플, 집합, 사전 내에서 쉼표 주위의 공백은 아무렇게나 사용해도 기능적으로 별 문제 없습니다. 하지만, 파이썬 스타일 가이드는 쉼표 앞 쪽에는 공백이 없어야 하고 뒤쪽으로는 하나가 와야 한다고 언급합니다. 이는 완전히 미적 취향의 문제이긴 하지만(코드는 어찌되었든 돌아갑니다. 파이썬 2, 3 모두에서요), 2to3 스크립트는 여러분이 원한다면 쉼표 주위의 공백을 수정할 수도 있습니다.

2to3 스크립트는 기본적으로 쉼표 주위의 공백을 수정하지 않습니다. 수정하고 싶으면 2to3를 호출할 때 명령행 인자로 -f wscomma를 지정하십시오.

Notes Before After
a ,b a, b

흔히 쓰이는 관용구(명시적)

파이썬 커뮤니티에서 쌓아올려진 일반적인 관용 표현이 몇 개 있습니다. 어떤 표현들, 예를 들어 while 1: 문 같은 표현의 기원을 찾으려면, 파이썬 1까지 거슬러 올라가야 합니다. (파이썬은 2.3 버전이 나오기 전까지 참(true)에 해당하는 boolean 형이 없었으므로, 개발자들은 1과 0을 대신 사용했습니다.) 최근 파이썬 프로그래머는 이런 관용 표현의 현대적인 표현을 머릿속에 입력해두는 편이 좋을 것 같습니다.

2to3 스크립트는 기본적으로 관용 표현을 수정하지 않습니다. 수정하고 싶으면 2to3를 호출할 때 명령행 인자로 -f idioms를 지정하십시오.

Notes Before After
while 1:
    do_stuff()
while True:
    do_stuff()
type(x) == T isinstance(x, T)
type(x) is T isinstance(x, T)
a_list = list(a_sequence)
a_list.sort()
do_stuff(a_list)
a_list = sorted(a_sequence)
do_stuff(a_list)

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

5171 읽음
이전 챕터 16. 파이썬 라이브러리 패키징하기
다음 부록 B. 특수 함수 이름

저자

토론이 없습니다

Please log in to leave a comment

16.5.11618.20190612.allo
문제 보고 · 사용조건 · 개인정보보호
래블업 주식회사 · 대한민국 서울 테헤란로 145 · 대표: 신정규 · 사업자번호: 864-88-00080 · +82 70-8200-2587

거절 확인

닫기
좋아요 책갈피 토론

아래 주소를 복사하세요