Edited at

Python2からPython3.0での変更点

More than 1 year has passed since last update.


初めに

この記事は、Python その2 Advent Calendar 2015の9日目の記事です。


書こうと思ったわけ

僕がPython初めて書いたのが4年前でとてもよい言語だと思い、簡単なコードなどはいつもPythonで書いていました。

初めに書いたのはPython2.7でしたが、調べていたらPython3なるものがあり、新しいもの好きだったので本気で学ぼうとし始めた時はPython3.3を使ってました。

なので、2系の話などはほとんど知らず、わざわざ古い(といっても当時は2系がメインでしたが)ものを学ぶ必要もないと思ってました。

が。

2系のライブラリが3系に対応していなかったり、2系で書かれていて3系に自分で置き換えなければならないなど色々問題がありました。

とまぁ、とにかく2系と3系の違いを学習ついでにまとめて見ようと思った次第です。

(すでに3系がでてから7年位経っているのは置いといて・・・)

(さらに、他の素晴らしい方々が素晴らしい記事を書いていらっしゃるのも置いといて・・・(T_T))


本題に入る前に・・


  • 書き始めた際はPython2からPython3.5までの経過を書こうと思ったのですが、Python3.0まででかなりの長さになったのでPython3.0からPython3.5までの経過は別記事に書きます。

  • コードを実行したバージョンは左上に書いてあります。

  • Pythonの知識がある程度ある方向けになっています。ちょろっと触ったことある方なら多分大丈夫!

  • コードの中に突如出てくるアンダーバーは一つ前の実行結果が格納されています。


Python3

>>> 1+1

2
>>> _
2
>>> 2+3
5
>>> _ -3
2
>>> type(_)
<class 'int'>
>>> _
<class 'int'>

それでは、結構長いですが(笑)

頑張ってきましょう!


Python2 -> Python3.0


printが文から関数に変更


Python2

>>> print 'Hello'

Hello


Python3

>>> print('Hello')

Hello

Python3での定義はこんな感じらしいです。

def print(*args, sep=' ', end='\n', file=None)

タプルを表示させようとした時とか困るのかな。


Python2

>>> print ('item1', 'item2')

('item1', 'item2')


Python3

>>> print ('item1', 'item2')

item1 item2
>>> print(('item1', 'item2'), )
('item1', 'item2')


リストの代わりにViewsやイテレータを返す

Viewsってナンノコッチャ。

まぁ、結果を見ればわかるでしょう。


dictのメソッド、keys, items, valuesはViewsを返す


Python2

>>> d = {"key1": "value1"}

>>> d.keys()
['key1']
>>> type(_)
<type 'list'>
>>> d.values()
['value1']
>>> d.items()
[('key1', 'value1')]


Python3

>>> d = {"key1": "value1"}

>>> d.keys()
<dict_keys object at 0x7f0da5268e18>
>>> type(_)
<class 'dict_keys'>
>>> d.values()
<dict_values object at 0x7f0da5268e18>
>>> d.items()
<dict_items object at 0x7f0da3a44638>

Python2では全てリストで、Python3ではdict_keysなどのオブジェクトとして返ってきてますね。

これはイテレート可能なオブジェクトで、これをViewsと呼んでいるのでしょう。

Python3でリストとして欲しければlist()でラップしましょう。


Python3

>>> list(d.keys())

['key1']


dictのメソッド、iterkeys, iteritems, itervaluesの廃止


Python2

>>> d.iterkeys()

<dictionary-keyiterator object at 0x7f5b586155d0>
>>> type(_)
<type 'dictionary-keyiterator'>


Python3

>>> d.iterkeys()

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'dict' object has no attribute 'iterkeys'

まー当たり前ですよね。keysがイテレーター返すんですから。


map, filter関数がイテレーターを返す


Python2

>>> f1 = lambda x : x + 1

>>> f2 = lambda x : x%2 == 0
>>> l = [1, 2, 3]
>>> map(f1, l)
[2, 3, 4]
>>> type(_)
<type 'list'>
>>> filter(f2, l)
[2]
>>> type(_)
<type 'list'>


Python3

>>> iter_check = lambda obj : hasattr(obj, '__iter__') and hasattr(obj, '__next__')

>>> isIterable = lambda obj : hasattr(obj, '__iter__')
>>> f1 = lambda x : x + 1
>>> f2 = lambda x : x%2 == 0
>>> l = [1, 2, 3]
>>> map(f1, l)
<map object at 0x7f0da5261950>
>>> map_obj = _
>>> type(map_obj)
<class 'map'>
>>> iter_check(map_obj)
True
>>>
>>> filter(f2, l)
<filter object at 0x7f0da52619d0>
>>> filter_obj = _
>>> type(filter_obj)
<class 'filter'>
>>> iter_check(filter_obj)
True

lambdaの所の内容はあまり気にしなくて大丈夫です(笑)

イテレート可能なオブジェクトなのかイテレーターなのかなどをチェックする関数です。

Python2ではリスト、Python3ではイテレーターが返ってきてますね。


Python3のrange関数はイテレータオブジェクトを返す(Python2でのxrange)。xrangeは廃止


Python2

>>> iter_check = lambda obj : hasattr(obj, '__iter__') and hasattr(obj, '__next__')

>>> isIterable = lambda obj : hasattr(obj, '__iter__')
>>> type(range(1,10))
<type 'list'>
>>> type(xrange(1,10))
<type 'xrange'>
>>> iter_check(xrange(1,10))
False
>>> isIterable(xrange(1,10))
True


Python3

>>> type(range(1,10))

<class 'range'>
>>> type(iter(range(1,10)))
<class 'range_iterator'>
>>> xrange(1,10)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'xrange' is not defined

Python3ではrangeがリストではなくイテレート可能なオブジェクトを返しています。

そしてxrangeはお亡くなりになりました。チーン


zip関数はイテレーターを返す


Python2

>>> zip([1,2,3], [2,3,4])

[(1, 2), (2, 3), (3, 4)]
>>> type(_)
<type 'list'>


Python3

>>> zip([1,2,3], [2,3,4])

<zip object at 0x7f0da3a40cf8>
>>> iter_check(_)
True

Python3ではイテレーターを返していますね。


順序比較


比較演算子(<, >, <=, >=)は、そのオペランドが自然な順序付けを持たない場合TypeErrorを送出する


Python2

>>> 1 < 'a'

True
>>> 0 > None
True
>>> len <= len
True
>>> None < None
False


Python3

>>> 1 < 'a'

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: int() < str()
>>> 0 > None
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: int() > NoneType()
>>> len <= len
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: builtin_function_or_method() <= builtin_function_or_method()
>>> None < None
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: NoneType() < NoneType()

これ、自分初めて知りました。Python2ひどいですね・・・。

ですがPython3ではしっかり例外を投げてくれるので安心ですね!


sorted関数とlistのsortメソッドは比較関数を与えるcmp引数を取らなくなった

Python2での定義は以下の通り

sorted(iterable[, cmp[, key[, reverse]]])

s.sort([cmp[, key[, reverse]]])

Python3での定義は以下の通り

sorted(iterable[, key][, reverse])

sort(*, key=None, reverse=None)

cmp引数、なくなってますね。

また、Python3でのlistのsortメソッドの引数はキーワード引数で渡す必要があります。


cmp関数は廃止され、__cmp__メソッドはサポートされない

これは例を出すとかではないですよねー。

ソートには__lt__メソッドを使用してくれとのことです。


整数について


基本的にlongはintに改名された(が、古いlong型とほぼ同様に振る舞う)


Python2

>>> type(10**100)

<type 'long'>


Python3

>>> type(10**100)

<class 'int'>

Pythonではint型として扱われていますね。


1/2のような式はfloatを型を返す。少数点以下切捨て場合は1//2のような式にすること


Python2

>>> 1/2

0
>>> type(1/2)
<type 'int'>


Python3

>>> type(1/2)

<class 'float'>
>>> 1//2
0
>>> type(1//2)
<class 'int'>

Python3で除算を行いintで返したい場合は//演算子を使いましょう。


整数の上限がなくなったためsys.maxint定数は削除された


Python2

>>> sys.maxint

9223372036854775807


Python3

>>> sys.maxint

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'maxint'

削除されてますね。


long整数のreprメソッドは末尾にLをつけない


Python2

>>> 10**20

100000000000000000000L


Python3

>>> 10**20

100000000000000000000

Python3ではLが末尾についていませんね。


8進数リテラルが0720のような表記から0o720というような表記に変更


Python2

>>> 0720

464
>>> 0o720
464


Python3

>>> 0720

File "<stdin>", line 1
0720
^
SyntaxError: invalid token
>>> 0o720
464

これは0xや0bなどの表記に統一された形でしょうか。


ユニコードと8bitの代わりにテキストとデータへ


全てのテキストはUnicodeに

タイトル通り。

これによって以前までのユニコードテキストのリテラルu"..."は使用できなくなった。


Python2

>>> u"unicode"

u'unicode'


Python3

>>> u"unicode"

File "<stdin>", line 1
u"unicode"
^
SyntaxError: invalid syntax


テキストはstr型、dataはbytes型


Python3

>>> type("test")

<class 'str'>
>>> type(b"test")
<class 'bytes'>

バイナリデータのリテラルにはb"..."を使用する。


テキストとdataを混ぜるとTypeErrorを送出する


Python2

>>> "str" + b"bytes"

'strbytes'


Python3

>>> "str" + b"bytes"

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't convert 'bytes' object to str implicitly

Python2まじかよ・・(2回目)

こんなの発狂ものですね。。Python3エラい!


テキストとdata間の明示的変換


Python3

>>> "str".encode()

b'str'
>>> bytes("str", "utf-8")
b'str'
>>>
>>> b"bytes".decode()
'bytes'
>>> str(b"bytes", "utf-8")
'bytes'

str, bytes間の変換ですね。

まぁ、Pythonでのencode、decodeの記事は山ほどありますからそちらを参考に・・・。


raw文字列内でもバックスラッシュはそのままの文字で解釈される


Python2

>>> print(ur"\u20ac")




Python3

>>> print(r"\u20ac")

\u20ac

Python2まじかよ、とまでは言いませんが、おいっ!

って感じですね。raw文字列のいみねーじゃん!

まぁ、こういう挙動をして欲しい場合もあるかもしれませんがPython3の挙動のほうがいいですよねー。


basestringという抽象クラスが削除


Python2

>>> str.__base__

<type 'basestring'>
>>> bytes.__base__
<type 'basestring'>


Python3

>>> str.__base__

<class 'object'>
>>> bytes.__base__
<class 'object'>

Python2ではbasestringという抽象クラスがあったのですね。それを継承してstr、bytes型ができてたということですね。

Python3では直接それぞれのクラスが定義されていますね。


構文の変更の概要


関数アノテーションの追加


Python3

>>> def f(a: "int_value", b: "int_value default value one" = 1) -> "added_value":

... return a+b
...
>>> f.__annotations__
{'a': 'int_value', 'b': 'int_value default value one', 'return': 'added_value'}

関数の引数や返り値にアノテーションを追加することができます。

上の例では文字列だけですが、式を書くことができるので、1+1intなどを書くことができます。


Python3

>>> i=2

>>> j=3
>>> def f(a: i*j, b: i+j) -> 1+1:
... return a+b
...
>>> f.__annotations__
{'a': 6, 'b': 5, 'return': 2}
>>> i=10
>>> j=10
>>> f.__annotations__
{'a': 6, 'b': 5, 'return': 2}

式は関数定義時に評価されます。当たり前っちゃ当たり前ですね。。


キーワードのみの引数


Python3

>>> def f(a, *, b):

... return a+b
...
>>> def g(*, a, b):
... return a*b
...
>>> f(1, 2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() takes exactly 1 positional argument (2 given)
>>> f(1, b=2)
3
>>> g(1, b=2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: g() takes exactly 0 non-keyword positional arguments (1 given)
>>> g(a=1, b=2)
2
>>> g(b=1, a=2)
2

アスタリスク*を使用してそれ以降に列挙される引数をキーワード引数限定とすることができます。

これ日本語の文献すっごく少なくって最初見た時は随分と困りました(笑)


クラス定義の基底クラスのリストの後にキーワード引数を渡せる


Python3

>>> class MClass(type):

... def __new__(cls, name, bases, namespace, **kwds):
... result = type.__new__(cls, name, bases, dict(namespace))
... result.members = tuple(namespace)
... return result
... def __init__(self, *args, **kargs):
... print("args: " + str(args))
... print("kargs: " + str(kargs))
...
>>> class A(object, metaclass=MClass, a=1, b=2, c=3):
... def one(self): pass
...
args: ('A', (<class 'object'>,), {'__module__': '__main__', 'one': <function one at 0x7f62d071c408>})
kargs: {'a': 1, 'c': 3, 'b': 2}

これ、内容が少しヘビーですね・・・。

ともかく基底クラスの後にキーワード引数を受け取ることができます。

ただし、typeではキーワード引数を受け取ることができないので、受け取れるようなmetaclassを自作しなければいけませんが。。(MClassがそれです)


nonlocal文


Python3

>>> def counter(init=0):

... def cntup():
... nonlocal init
... init+=1
... return init
... return cntup
...
>>> c = counter()
>>> c()
1
>>> c()
2
>>> c()
3

nonlocal文は指定された識別子を一つ上のスコープにある変数を参照できるようにします。

要はクロージャーですかね。

例ではcounter関数の引数initをnonlocal文で参照していますね。

Python2ではlistなどを用いてゴニョゴニョしなければできなかったのですが、Python3では簡潔に書けますね。

(参照するだけであればnonlocalやPython2でのlistなどは必要ない。外側のスコープの変数に束縛を行う際に必要)


Python3

>>> c.__closure__

(<cell at 0x7f62d071d5c8: int object at 0x7a3e20>,)
>>> c.__closure__[0].cell_contents
3

ついでにこのような形でクロージャーを参照できます。


拡張Iterable Unpacking


Python3

>>> a, *rest, b = range(5)

>>> a
0
>>> rest
[1, 2, 3]
>>> b
4

restにaとbにUnpack後、余ったものをリストとしてUnpackされる。

このrestは空リストとしてUnpackされることもある。


Python3

>>> a, *rest, b = range(2)

>>> a
0
>>> rest
[]
>>> b
1

これはすごい・・・。


変更された構文


例外のキャッチの構文


Python2

>>> try:

... raise Exception("test")
... except Exception, e:
... print "catch exception!"
...
catch exception!


Python3

>>> try:

... raise Exception("test")
... except Exception as e:
... print("catch exception!")
...
catch exception!

カンマからasキーワードに変更されていますね。


新たなraise文のシンタックス


Python3

>>> try:

... raise Exception("test")
... except Exception as e:
... raise RuntimeError("catch exception!") from e
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
Exception: test

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
File "<stdin>", line 4, in <module>
RuntimeError: catch exception!


from節が追加され、例外の連鎖を表現できるようになりました。

また、except節で例外が送出された場合も暗黙的に働くそうですよ。


Python3

>>> try:

... 1/0
... except Exception as e:
... raise RuntimeError("raise exception.")
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
ZeroDivisionError: int division or modulo by zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "<stdin>", line 4, in <module>
RuntimeError: raise exception.



True, Falseが予約語に


Python2

>>> True = 0

>>> False = 1
>>> True
0
>>> False
1
>>> True and True
0


Python3

>>> True=0

File "<stdin>", line 1
SyntaxError: assignment to keyword
>>> False=1
File "<stdin>", line 1
SyntaxError: assignment to keyword

恐怖!!

ってかまぁTrue,Falseに代入したり、普通は!しないですけどね。


メタクラスのシンタックスの変更


Python2

>>> class M(type):

... pass
...
>>> class C:
... __metaclass__ = M
...
>>> C.__class__
<class '__main__.M'>


Python3

>>> class M(type):

... pass
...
>>> class C(metaclass=M):
... pass
...
>>> C.__class__
<class '__main__.M'>

Python2では__metaclass__変数、Python3では基底クラスを指定するとこにキーワード引数として渡します。

Python3ではPython2のような手段はサポートしていません。

ここで初めて知ったのが、Python2ではclassでobjectを明示的に継承しないといけなかったのですが、メタクラスを利用することでobjectを継承したクラスができることでした。なるほど!


Python2

>>> class A:

... pass
...
>>> A.__bases__
()
>>> class C:
... __metaclass__ = type
...
>>> C.__bases__
(<type 'object'>,)


ellipsisはどこででも原始的な式として使用できる


Python3

>>> ...

Ellipsis
>>> def e():
... ...

省略。(まじで言うことがない・・・)


削除された操作

削除されたものなのでさーっといきます。


タプル引数のアンパック


Python2

>>> def foo(a, (b,c)):

... return a+b+c
...
>>> t = 2,3
>>> foo(1, t)
6


Python3

>>> def foo(a, (b,c)):

File "<stdin>", line 1
def foo(a, (b,c)):
^
SyntaxError: invalid syntax

読みづらいですねぇ・・・。

Python3では1行目から怒られます。


バッククオートについて


Python2

>>> i = 123

>>> `i`
'123'


Python3

>>> i=123

>>> `i`
File "<stdin>", line 1
`i`
^
SyntaxError: invalid syntax

どうやら__repr__メソッドが呼ばれていたようです。


execについて


Python2

>>> exec "print('python2')"

python2
>>> exec("print('python2')")
python2


Python3

>>> exec "print('python3')"

File "<stdin>", line 1
exec "print('python3')"
^
SyntaxError: invalid syntax
>>> exec("print('python3')")
python3

Python2ではexec文でした。関数表記も大丈夫です。

Python3では予約語ではなくなり、関数として残りました。


<>演算子


Python2

>>> 1 <> 2

True
>>> 1 <> 1
False


Python3

>>> 1 <> 2

File "<stdin>", line 1
1 <> 2
^
SyntaxError: invalid syntax

!=でいいじゃないですかねぇ。


リテラル周り


Python2

>>> u"python2"

u'python2'
>>> 100L
100L


Python3

>>> u"python3"

File "<stdin>", line 1
u"python3"
^
SyntaxError: invalid syntax
>>> 100L
File "<stdin>", line 1
100L
^
SyntaxError: invalid syntax

上の方で既に述べている内容ですね。


トップレベル以外でのfrom module import *について


Python2

>>> from sys import *

>>> def f():
... from os import *
...
<stdin>:1: SyntaxWarning: import * only allowed at module level


Python3

>>> from sys import *

>>> def f():
... from os import *
...
File "<stdin>", line 1
SyntaxError: import * only allowed at module level

WarningからErrorになってますね。なんでPython2はWarningで止めたんだろうか・・・


その他の変更


演算子と特殊メソッド


!===と逆の結果を返す(==がNotImplementedを返さない場合は)


Python2

>>> class C:

... def __init__(self, a):
... self.a = a
...
... def __eq__(self, other):
... return self.a == other.a
...
>>> a = C(1)
>>> b = C(1)
>>> c = C(2)
>>> a == b
True
>>> a == c
False
>>> a != b
True
>>> a != c
True


Python3

>>> class C:

... def __init__(self, a):
... self.a = a
...
... def __eq__(self, other):
... return self.a == other.a
...
>>> a = C(1)
>>> b = C(1)
>>> c = C(2)
>>> a == b
True
>>> a != b
False
>>> a == c
False
>>> a != c
True

これちょっと意外でした。

Python2の!=__ne__()を実装していないのでオブジェクトが同一のものかを比較しています。

a, b, cはどれも別物なので結果がTrueになっています。

自分はてっきりAttributeErrorが出るのかと思ってました・・・。少し考えれば分かる話でしたね。


unbound methodsからfunction objectへ


Python2

>>> class C:

... def f(self):
... pass
...
>>> C.f
<unbound method C.f>


Python3

>>> class C:

... def f(self):
... pass
...
>>> C.f
<function f at 0x100a35270>

はい。Python3がただの関数として扱われています。

unbound methodはインスタンスに紐付いていないメソッドということでしょう。

Python3のほうが単純明快で分かりやすいですね


__getslice__()系のメソッドは削除され、__getitem__()系のメソッドにsliceオブジェクトが渡される


Python2

>>> class C:

... def __getslice__(self, i, j):
... print i, j
... raise NotImplementedError()
...
>>> a = C()
>>> a[0:2]
0 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in __getslice__
NotImplementedError


Python3

>>> class C:

... def __getitem__(self, obj):
... print(obj)
... print(type(obj))
... raise NotImplementedError()
...
>>> a = C()
>>> a[0:2]
slice(0, 2, None)
<class 'slice'>
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in __getitem__
NotImplementedError


  • getslice

  • setslice

  • delslice


  • getitem

  • setitem

  • delitem

を代わりに呼ぶようになり、スライスオブジェクトが渡されるように変わりました。

例では実装をしていませんが、引数にスライスオブジェクトが渡されているのがわかりますね。


next()メソッドは__next__()に改名された


Python2

>>> class C:

... def __iter__(self):
... return self
...
... def next(self):
... return 0
...
>>> a = C()
>>> i = iter(a)
>>> next(i)
0
>>> i.next()
0


Python3

>>> class C:

... def __iter__(self):
... return self
...
... def __next__(self):
... return 0
...
>>> a = C()
>>> i = iter(a)
>>> next(a)
0
>>> i.__next__()
0

next()から__next__()が呼ばれるように変わっていますね。


__oct__()__hex__()は削除され、__index__()を使用すること


Python2

>>> class C:

... def __oct__(self):
... return "07"
...
... def __hex__(self):
... return "0x7"
...
>>> a = C()
>>> hex(a)
'0x7'
>>> oct(a)
'07'


Python3

>>> class C:

... def __index__(self):
... return 7
...
>>> a = C()
>>> hex(a)
'0x7'
>>> oct(a)
'0o7'

__oct__()__hex__()は数値を文字列に変換して返すメソッドなのですが、__index__()は数値を返すだけです。後はPythonが良しなに変換してくれます。

Python3素晴らしい〜。

(例は定数返してますがご勘弁を・・・)


__nonzero__()__bool__()に改名された


Python2

>>> class C:

... def __nonzero__(self):
... return True
...
>>> a = C()
>>> bool(a)
True


Python3

>>> class C:

... def __bool__(self):
... return True
...
>>> a = C()
>>> bool(a)
True

__nonzero__()ってどういう流れで名前が決まったんですかね・・・。

Python3では__bool__()が呼ばれています。分かりやすい。


Builtins


super()の追加


Python3

>>> class SuperClass:

... pass
...
>>> class SubClass(SuperClass):
... def findSuperClass(self):
... print("call super(): ", super())
... print("call super(SubClass, self)", super(SubClass, self))
...
>>> i = SubClass()
>>> i.findSuperClass()
call super(): <super: <class 'SubClass'>, <SubClass object>>
call super(SubClass, self) <super: <class 'SubClass'>, <SubClass object>>

super()は引数無しで呼び出すことができ、適切なクラスとインスタンスを自動的に選んでくれます。

引数がある時と処理は特には変わりません。


raw_input()input()に改名


Python3

>>> input()

test
'test'

input()は標準入力から1行読み取り、改行を除いた文字列を返します。

Python2でのinput()を実行したい場合はeval(input())で実現できます。


まとめ

ぶっちゃけPython3では


  • printが関数に

  • keys, items, valuesメソッドはイテレート可能なオブジェクトを返す

  • 文字列の標準がUnicodeになり型がstr

  • xrangeがrangeに

辺りを覚えておけば殆ど支障はないと思います。

また、この記事で省いた変更点がいくつかあるのですが、ニッチな内容であまり重要でない気がしたものを全体の1割ほど削っています。知りたい方はWhat's New in Python3.0読んでください(丸投げ)。


終わりに

記事を書いてて思ったことですが、Python2で罠にハマりそうな点がいくつかあってびっくりしました。

自分でやり始めたのがPython3からで良かったです(笑)

そしてまだPython2から乗り換えてない方は便利にこれを機会に覚えていただいてPython3に乗り換えると幸せなPythonライフが待っているのではないでしょうか(笑)

(Python2から3とかもう随分たっててまとめ系の記事は沢山ありますが・・・)

冒頭でも書きましたが、Python3.0からPython3.5までの経過は別記事で書こうと思います。

Python3.0からPython3.5までの経過はPython その2 Advent Calendar の16日にのせるつもりです。

また、変な点や間違い、こうした方が良いなどありましたらコメントくださるとありがたいです!

明日は空きで、11日は@FGtatsuroです!

それでは良きPython3ライフを!!