Python Language
Python 2からPython 3への非互換性
サーチ…
前書き
ほとんどの言語とは異なり、Pythonは2つのメジャーバージョンをサポートしています。 Python 3がリリースされた2008年以来、多くの人が移行を行いましたが、多くはそうしていませんでした。両方を理解するために、このセクションではPython 2とPython 3の重要な違いについて説明します。
備考
現在サポートされているPythonのバージョンは2.7(Python 2)と3.6(Python 3)です。さらに、バージョン3.3および3.4は、ソース形式でセキュリティ更新プログラムを受信します。
Python 2.7はほとんどの旧バージョンのPythonと下位互換性があり、Pythonのほとんどの1.xおよび2.xバージョンのPythonコードを変更せずに実行できます。これは広範囲に利用可能であり、広範なパッケージを集めています。また、CPython開発者は非推奨と見なされ、セキュリティとバグ修正の開発のみを受け取ります。 CPythonの開発者は、このバージョンの言語を2020年に放棄しようとしています。
Python Enhancement Proposal 373によれば、2016年6月25日以降、Python 2の将来のリリースは予定されていませんが、2020年まではバグ修正やセキュリティアップデートがサポートされます。(2020年の正確な日付はPythonの2)
Python 3は、言語開発者が言語の核心にあった懸念に対処するために意図的に下位互換性を破った。 Python 3は新しい開発と新機能を受け取ります。これは、言語開発者が前進する予定の言語のバージョンです。
Python 3.0の初期リリースから現在のバージョンまでの間に、Python 3のいくつかの機能はPython 2.6にバックポートされ、Python 3の他の部分はPython 2との構文互換性が拡張されました。したがって、 Python 2とPython 3の両方で、将来のインポートと特別なモジュール( 6のような)を使って動作するPython。
将来のインポートは、モジュールの始めにある必要があります。
from __future__ import print_function
# other imports and instructions go after __future__
print('Hello world')
__future__
モジュールの詳細については、Pythonドキュメントの関連ページを参照してください 。
2to3ツールは、Python 2.xコードをPython 3.xコードに変換するPythonプログラムです ( Pythonのドキュメントも参照してください)。
パッケージ6はPython 2/3との互換性のためのユーティリティを提供します:
- 名前を変更したライブラリへの統一されたアクセス
- 文字列/ユニコードタイプの変数
- 削除されたメソッドまたは名前が変更されたメソッドの関数
Python 2とPython 3の相違点については、ここで参照できます 。
印刷ステートメントと印刷機能
Python 2では、 print
はステートメントです:
print "Hello World"
print # print a newline
print "No newline", # add trailing comma to remove newline
print >>sys.stderr, "Error" # print to stderr
print("hello") # print "hello", since ("hello") == "hello"
print() # print an empty tuple "()"
print 1, 2, 3 # print space-separated arguments: "1 2 3"
print(1, 2, 3) # print tuple "(1, 2, 3)"
Python 3では、 print()
は汎用のキーワード引数を持つ関数です:
print "Hello World" # SyntaxError
print("Hello World")
print() # print a newline (must use parentheses)
print("No newline", end="") # end specifies what to append (defaults to newline)
print("Error", file=sys.stderr) # file specifies the output buffer
print("Comma", "separated", "output", sep=",") # sep specifies the separator
print("A", "B", "C", sep="") # null string for sep: prints as ABC
print("Flush this", flush=True) # flush the output buffer, added in Python 3.3
print(1, 2, 3) # print space-separated arguments: "1 2 3"
print((1, 2, 3)) # print tuple "(1, 2, 3)"
印刷機能には、次のパラメータがあります。
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
sep
は、渡すオブジェクトを区切って印刷するものです。例えば:
print('foo', 'bar', sep='~') # out: foo~bar
print('foo', 'bar', sep='.') # out: foo.bar
end
はprintステートメントの終わりの後に続くものです。例えば:
print('foo', 'bar', end='!') # out: foo bar!
同じ行に印刷されます print文を終了する非改行、次の再印刷:
print('foo', end='~')
print('bar')
# out: foo~bar
注意:将来の互換性のために、 print
機能はPython 2.6以降でも利用できます。ただし、 print
ステートメントの解析が無効にされていない限り使用することはできません
from __future__ import print_function
この関数は、 flush
パラメータがない点を除いて、Python 3とまったく同じ形式です。
根拠については、PEP 3105を参照してください。
文字列:バイトとUnicode
Python 2には、文字列型( str
)のバイトとstr
のテキスト( unicode
)からなる2種類の文字列があります。
Python 2では、 str
型のオブジェクトは常にバイトシーケンスですが、テキストデータとバイナリデータの両方によく使用されます。
文字列リテラルはバイト文字列として解釈されます。
s = 'Cafe' # type(s) == str
2つの例外があります。Unicode(text)リテラルを明示的に定義するには、リテラルにu
:
s = u'Café' # type(s) == unicode
b = 'Lorem ipsum' # type(b) == str
あるいは、モジュール全体の文字列リテラルがUnicode(テキスト)リテラルを作成するように指定することもできます。
from __future__ import unicode_literals
s = 'Café' # type(s) == unicode
b = 'Lorem ipsum' # type(b) == unicode
変数が文字列(Unicodeかバイト文字列)かどうかを確認するには、次のようにします:
isinstance(s, basestring)
Python 3では、 str
型はUnicodeテキスト型です。
s = 'Cafe' # type(s) == str
s = 'Café' # type(s) == str (note the accented trailing e)
さらに、Python 3では、バイナリの「ブロブ」やエンコードに依存しないファイルへの書き込みに適したbytes
オブジェクトが追加されました。バイトオブジェクトを作成するには、 b
を文字列リテラルに接頭するか、文字列のencode
メソッドを呼び出します。
# Or, if you really need a byte string:
s = b'Cafe' # type(s) == bytes
s = 'Café'.encode() # type(s) == bytes
値が文字列かどうかをテストするには、次のようにします。
isinstance(s, str)
Python 2とPython 3のコードベース間の互換性を容易にするために、文字列リテラルに接頭辞u
付けることもできます。 Python 3では、すべての文字列がデフォルトでUnicodeなので、文字列リテラルの前にu
ても効果はありません。
u'Cafe' == 'Cafe'
Python 2の生のUnicode文字列の接頭辞ur
はサポートされていません。
>>> ur'Café'
File "<stdin>", line 1
ur'Café'
^
SyntaxError: invalid syntax
Python 3 text( str
)オブジェクトをencode
、そのテキストのbytes
表現に変換する必要があることに注意してください。このメソッドのデフォルトのエンコーディングはUTF-8です。
decode
を使ってbytes
オブジェクトに、それが表すUnicodeテキストを尋ねることができます:
>>> b.decode()
'Café'
bytes
タイプはPython 2と3の両方に存在しbytes
が、 unicode
型はPython 2にのみ存在します。Python 2でPython 3の暗黙のUnicode文字列を使用するには、コードファイルの先頭に次のコードを追加します。
from __future__ import unicode_literals
print(repr("hi"))
# u'hi'
もう1つの重要な違いは、Python 3のインデックスバイトがint
出力になることです。
b"abc"[0] == 97
1のサイズでスライスすると、長さが1バイトのオブジェクトになります。
b"abc"[0:1] == b"a"
さらに、Python 3はユニコードでいくつかの異常な動作を修正します。つまり、Python 2でバイト文字列を反転します。たとえば、 次の問題が解決されました。
# -*- coding: utf8 -*-
print("Hi, my name is Łukasz Langa.")
print(u"Hi, my name is Łukasz Langa."[::-1])
print("Hi, my name is Łukasz Langa."[::-1])
# Output in Python 2
# Hi, my name is Łukasz Langa.
# .agnaL zsakuŁ si eman ym ,iH
# .agnaL zsaku�� si eman ym ,iH
# Output in Python 3
# Hi, my name is Łukasz Langa.
# .agnaL zsakuŁ si eman ym ,iH
# .agnaL zsakuŁ si eman ym ,iH
整数部
標準除算記号 ( /
)は、整数に適用すると、Python 3とPython 2では動作が異なります。
Python 3で整数を別の整数で割ると、除算演算x / y
は真の除算を表し( __truediv__
メソッドを使用)、浮動小数点の結果を生成します。一方、パイソン2における同様の動作を表す古典的な分割 (また床を取るとしても知られる)負の無限大に向かってダウン結果を丸めます。
例えば:
コード | Python 2の出力 | Python 3の出力 |
---|---|---|
3 / 2 | 1 | 1.5 |
2 / 3 | 0 | 0.6666666666666666 |
-3 / 2 | -2 | -1.5 |
ゼロへの丸めの振る舞いは、 Python 2.2では廃止されましたが、後方互換性のためにPython 2.7に残っており、Python 3では削除されています。
注意: Python 2で浮動小数点の結果を得るには(フロアの丸めなし)、オペランドの1つを小数点で指定します。上記のPython 2で0
を与える2/3
例は、 2 / 3.0
または2.0 / 3
または2.0/3.0
として使用され、 0.6666666666666666
コード | Python 2の出力 | Python 3の出力 |
---|---|---|
3.0 / 2.0 | 1.5 | 1.5 |
2 / 3.0 | 0.6666666666666666 | 0.6666666666666666 |
-3.0 / 2 | -1.5 | -1.5 |
フロア分割演算子 ( //
)もあり、両方のバージョンで同じように動作します。最も近い整数に切り下げられます。 (浮動小数点で使用すると浮動小数点が返されますが)どちらのバージョンでも、 //
演算子は__floordiv__
マップされ__floordiv__
。
コード | Python 2の出力 | Python 3の出力 |
---|---|---|
3 // 2 | 1 | 1 |
2 // 3 | 0 | 0 |
-3 // 2 | -2 | -2 |
3.0 // 2.0 | 1.0 | 1.0 |
2.0 // 3 | 0.0 | 0.0 |
-3 // 2.0 | -2.0 | -2.0 |
operator
モジュール内のネイティブ関数を使用して、真の除算またはフロア除算を明示的に実行することができます。
from operator import truediv, floordiv
assert truediv(10, 8) == 1.25 # equivalent to `/` in Python 3
assert floordiv(10, 8) == 1 # equivalent to `//`
明確で明示的ですが、すべての部門で演算子関数を使用するのは面倒です。 /
演算子の動作を変更する方が望ましいことが多い。一般的な方法はfrom __future__ import division
を各モジュールの最初のステートメントとして追加することによって、典型的な除算の振る舞いを排除することです。
# needs to be the first statement in a module
from __future__ import division
コード | Python 2の出力 | Python 3の出力 |
---|---|---|
3 / 2 | 1.5 | 1.5 |
2 / 3 | 0.6666666666666666 | 0.6666666666666666 |
-3 / 2 | -1.5 | -1.5 |
from __future__ import division
は、 /
演算子が__future__
importを含むモジュール内でのみ真の除算を表していることを保証するので、すべての新しいモジュールでそれを有効にしない魅力的な理由はありません。
注 :他のいくつかのプログラミング言語は、Pythonが負の無限大の方向に丸めるのではなく、 ゼロに切り捨てる(truncation)ようにします(つまり、それらの言語では-3 / 2 == -1
)。この動作は、コードの移植または比較時に混乱を招く可能性があります。
浮動小数点型のオペランドに関する注意 : from __future__ import division
代わりに、通常の除算シンボル/
を使用し、オペランドの少なくとも1つがfloat: 3 / 2.0 == 1.5
ことを確認することができます。しかし、これは悪い習慣とみなすことができます。 average = sum(items) / len(items)
を書いてfloatに引数の1つをキャストするのを忘れるのは簡単です。あなたが入った配列でテストする場合はさらに、このようなケースはしばしば、例えば、テスト中に通知を回避するfloat
秒が、配列受け取るint
生産で秒。さらに、同じコードがPython 3で使用されている場合、 3 / 2 == 1
がTrueであると予想されるプログラムは正しく動作しません。
除算演算子がPython 3で変更された理由と古いスタイルの除算を避ける理由については、 PEP 238を参照してください。
除算の詳細については、「 単純な数学」のトピックを参照してください。
Reduceはもはやビルトインではありません
Python 2では、 reduce
は組み込み関数またはfunctools
パッケージ(バージョン2.6以降)から利用できますが、Python 3ではreduce
はfunctools
からのみ利用できます。ただしの構文reduce
Python2とのpython3の両方では同じであり、であるreduce(function_to_reduce, list_to_reduce)
。
一例として、隣接する数値のそれぞれを分割することによってリストを単一の値に減らすことを考えてみましょう。ここでは、 operator
ライブラリの関数truediv
を使用します。
Python 2.xでは以下のように簡単です:
>>> my_list = [1, 2, 3, 4, 5]
>>> import operator
>>> reduce(operator.truediv, my_list)
0.008333333333333333
Python 3.xでは、この例は少し複雑になりました。
>>> my_list = [1, 2, 3, 4, 5]
>>> import operator, functools
>>> functools.reduce(operator.truediv, my_list)
0.008333333333333333
またfrom functools import reduce
を使用from functools import reduce
て、名前空間名でreduce
を呼び出さないようにreduce
こともできます。
範囲関数とxrange関数の違い
Python 2では、 range
関数はリストを返しますが、 xrange
は特殊なxrange
オブジェクトを作成します。これは他の組み込みシーケンス型と異なり、スライシングをサポートせず、 index
メソッドもcount
メソッドもありません。
print(range(1, 10))
# Out: [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(isinstance(range(1, 10), list))
# Out: True
print(xrange(1, 10))
# Out: xrange(1, 10)
print(isinstance(xrange(1, 10), xrange))
# Out: True
Python 3では、 xrange
がrange
シーケンスに展開され、 range
オブジェクトが作成されました。 xrange
タイプはありません:
print(range(1, 10))
# Out: range(1, 10)
print(isinstance(range(1, 10), range))
# Out: True
# print(xrange(1, 10))
# The output will be:
#Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
#NameError: name 'xrange' is not defined
さらに、Python 3.2以降、 range
はスライシング、 index
、およびcount
もサポートしていcount
:
print(range(1, 10)[3:7])
# Out: range(3, 7)
print(range(1, 10).count(5))
# Out: 1
print(range(1, 10).index(7))
# Out: 6
リストの代わりに特殊なシーケンス型を使用する利点は、インタプリタがリストのメモリを割り当てて、それを移入する必要がないことです。
# range(10000000000000000)
# The output would be:
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# MemoryError
print(xrange(100000000000000000))
# Out: xrange(100000000000000000)
後者の動作は一般的には望ましいので、Python 3では前者が削除されました。Python 3でリストを作成したい場合は、 range
オブジェクトでlist()
コンストラクタを使うだけです:
print(list(range(1, 10)))
# Out: [1, 2, 3, 4, 5, 6, 7, 8, 9]
互換性
Python 2.xとPython 3.xの両方のバージョン間の互換性を維持するために、 future
の外部パッケージからbuiltins
モジュールを使用して、 前方互換性と後方 互換性の両方を達成することができます。
#forward-compatible
from builtins import range
for i in range(10**8):
pass
#backward-compatible
from past.builtins import xrange
for i in xrange(10**8):
pass
future
ライブラリのrange
は、Python 3.2以降の組み込みメソッドと同様に、すべてのPythonバージョンでスライス、 index
、およびcount
サポートしています。
イテラブルの開梱
Python 3では、反復可能な要素の正確な数を知らずに反復可能なものをアンパックすることができ、反復可能な変数の終わりを保持する変数を持つことさえできます。そのために、値のリストを収集する変数を指定します。これは、名前の前にアスタリスクを置くことによって行われます。たとえば、 list
アンパック:
first, second, *tail, last = [1, 2, 3, 4, 5]
print(first)
# Out: 1
print(second)
# Out: 2
print(tail)
# Out: [3, 4]
print(last)
# Out: 5
注 : *variable
構文を使用する場合、元のタイプがリストでなくても、 variable
は常にリストになります。元のリストの要素の数に応じて、0個以上の要素を含むことがあります。
first, second, *tail, last = [1, 2, 3, 4]
print(tail)
# Out: [3]
first, second, *tail, last = [1, 2, 3]
print(tail)
# Out: []
print(last)
# Out: 3
同様に、 str
:
begin, *tail = "Hello"
print(begin)
# Out: 'H'
print(tail)
# Out: ['e', 'l', 'l', 'o']
date
のアンパックの例。 _
は、この例では使い捨て変数として使用されています(私たちはyear
値だけに興味があります):
person = ('John', 'Doe', (10, 16, 2016))
*_, (*_, year_of_birth) = person
print(year_of_birth)
# Out: 2016
*
は可変個数のアイテムを食べるので、割り当て内で同じiterableに対して 2つの*
持つことはできません - 最初のアンパックに入る要素の数と2番目のアンパックの数は分かりません:
*head, *tail = [1, 2]
# Out: SyntaxError: two starred expressions in assignment
これまでは、割り当ての解凍について議論しました。 *
と**
はPython 3.5で拡張されました 。 1つの式で複数のアンパック操作を行うことが可能になりました。
{*range(4), 4, *(5, 6, 7)}
# Out: {0, 1, 2, 3, 4, 5, 6, 7}
iterableを関数の引数に展開することも可能です:
iterable = [1, 2, 3, 4, 5]
print(iterable)
# Out: [1, 2, 3, 4, 5]
print(*iterable)
# Out: 1 2 3 4 5
辞書を展開すると、隣接する2つの星**
使用されます( PEP 448 )。
tail = {'y': 2, 'z': 3}
{'x': 1, **tail}
# Out: {'x': 1, 'y': 2, 'z': 3}
これにより、古い値を上書きして辞書をマージすることができます。
dict1 = {'x': 1, 'y': 1}
dict2 = {'y': 2, 'z': 3}
{**dict1, **dict2}
# Out: {'x': 1, 'y': 2, 'z': 3}
Python 3は、関数内のタプルのアンパックを削除しました。したがって、以下はPython 3では動作しません
# Works in Python 2, but syntax error in Python 3:
map(lambda (x, y): x + y, zip(range(5), range(5)))
# Same is true for non-lambdas:
def example((x, y)):
pass
# Works in both Python 2 and Python 3:
map(lambda x: x[0] + x[1], zip(range(5), range(5)))
# And non-lambdas, too:
def working_example(x_y):
x, y = x_y
pass
詳細な根拠については、PEP 3113を参照してください。
例外の発生と処理
これは、Pythonの2構文で、カンマに注意し,
上のraise
及びexcept
ラインを:
try:
raise IOError, "input/output error"
except IOError, exc:
print exc
Python 3では,
構文が削除され、かっことas
キーワードで置き換えられます。
try:
raise IOError("input/output error")
except IOError as exc:
print(exc)
下位互換性を保つために、Python 3以降の構文でもPython 3の構文を利用できるため、以前のバージョンと互換性がある必要のないすべての新しいコードに使用する必要があります。
Python 3では、 例外の連鎖も追加されています 。そこで、この例外の原因が他のいくつかの例外であることを伝えることができます。例えば
try:
file = open('database.db')
except FileNotFoundError as e:
raise DatabaseError('Cannot open {}') from e
except
文で発生する例外はDatabaseError
型ですが、元の例外はその例外の__cause__
属性としてマークされています。トレースバックが表示されると、元の例外もトレースバックに表示されます。
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
FileNotFoundError
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
DatabaseError('Cannot open database.db')
明示的な連鎖をせずにexcept
ブロックを投げた場合:
try:
file = open('database.db')
except FileNotFoundError as e:
raise DatabaseError('Cannot open {}')
トレースバックは
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
FileNotFoundError
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
DatabaseError('Cannot open database.db')
どちらもPython 2.xではサポートされていません。 exceptブロックで別の例外が発生した場合、元の例外とそのトレースバックは失われます。互換性のために次のコードを使用できます。
import sys
import traceback
try:
funcWithError()
except:
sys_vers = getattr(sys, 'version_info', (0,))
if sys_vers < (3, 0):
traceback.print_exc()
raise Exception("new exception")
以前にスローされた例外を "忘れる"には、 raise from None
使用します。
try:
file = open('database.db')
except FileNotFoundError as e:
raise DatabaseError('Cannot open {}') from None
トレースバックは単純に
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
DatabaseError('Cannot open database.db')
または、Python 2と3の両方と互換性を持たせるには、次のように6つのパッケージを使用します:
import six
try:
file = open('database.db')
except FileNotFoundError as e:
six.raise_from(DatabaseError('Cannot open {}'), None)
イテレータの.next()メソッドの名前が変更されました
Python 2では、イテレータ自体でnext
というメソッドを使用して、イテレータをトラバースすることができます。
g = (i for i in range(0, 3))
g.next() # Yields 0
g.next() # Yields 1
g.next() # Yields 2
Python 3では、 .next
メソッドの名前が.__next__
に変更され、 "magic"ロールとして.next
されます。したがって、 .next
を呼び出すとAttributeError
ます。 Python 2とPython 3の両方でこの機能にアクセスする正しい方法は、イテレータを引数としてnext
関数を呼び出すことです。
g = (i for i in range(0, 3))
next(g) # Yields 0
next(g) # Yields 1
next(g) # Yields 2
このコードは、2.6から現在のリリースまでのバージョン間で移植可能です。
異なるタイプの比較
異なるタイプのオブジェクトを比較することができます。結果は任意ですが一貫しています。それらは、 None
が他よりも少なく、数値型が非数値型よりも小さく、その他すべてが型によって辞書順に並べられるように順序付けられます。したがって、 int
はstr
より小さく、 tuple
はlist
よりも大きい:
[1, 2] > 'foo'
# Out: False
(1, 2) > 'foo'
# Out: True
[1, 2] > (1, 2)
# Out: False
100 < [1, 'x'] < 'xyz' < (1, 'x')
# Out: True
これはもともとは、混合型のリストをソートすることができ、オブジェクトを型ごとにグループ化するために行われました。
l = [7, 'x', (1, 2), [5, 6], 5, 8.0, 'y', 1.2, [7, 8], 'z']
sorted(l)
# Out: [1.2, 5, 7, 8.0, [5, 6], [7, 8], 'x', 'y', 'z', (1, 2)]
異なる(数値以外の)型を比較するときに例外が発生します。
1 < 1.5
# Out: True
[1, 2] > 'foo'
# TypeError: unorderable types: list() > str()
(1, 2) > 'foo'
# TypeError: unorderable types: tuple() > str()
[1, 2] > (1, 2)
# TypeError: unorderable types: list() > tuple()
Python 3で混合リストを型別にソートし、バージョン間の互換性を実現するには、ソートされた関数にキーを提供する必要があります。
>>> list = [1, 'hello', [3, 4], {'python': 2}, 'stackoverflow', 8, {'python': 3}, [5, 6]]
>>> sorted(list, key=str)
# Out: [1, 8, [3, 4], [5, 6], 'hello', 'stackoverflow', {'python': 2}, {'python': 3}]
key
関数としてstr
を使用すると、比較の目的でのみ各項目が一時的に文字列に変換されます。それから、 [
、 '
、 {
0-9
いずれかで始まる文字列表現を見ると、それらの文字列をすべてソートすることができます。
ユーザー入力
Python 2では、 raw_input
関数を使用してユーザー入力を受け入れ、
user_input = raw_input()
Python 3では、 input
関数を使用してユーザー入力を受け入れます。
user_input = input()
Python 2では、 input
関数は入力を受け入れて解釈します。これは便利ですが、いくつかのセキュリティ上の考慮事項があり、Python 3では削除されました。同じ機能にアクセスするには、 eval(input())
を使用できます。
スクリプトを2つのバージョン間で移植可能にするには、以下のコードをPythonスクリプトの最上部の近くに置くことができます。
try:
input = raw_input
except NameError:
pass
ディクショナリ方式の変更
Python 3では、辞書メソッドの多くはPython 2とはかなり違っていて、多くは削除されています: has_key
、 iter*
、 view*
はなくなりました。長い間廃止されていたd.has_key(key)
代わりにkey in d
使用する必要があります。
Python 2では、辞書のメソッドのkeys
、 values
、およびitems
はリストを返します。 Python 3では、代わりにビューオブジェクトを返します 。ビュー・オブジェクトはイテレータではなく、次の2つの点で異なります。
- 彼らはサイズを持っています(1つは
len
関数を使うことができます) - 彼らは何度も繰り返すことができます
さらに、イテレータと同様に、ディクショナリの変更はビュー・オブジェクトに反映されます。
Python 2.7は、これらのメソッドをPython 3からバックポートしました。 viewkeys
、 viewvalues
viewkeys
、 viewvalues
として利用できviewitems
。 Python 2コードをPython 3コードに変換するには、対応するフォームを以下のようにします。
- Python 2の
d.keys()
、d.values()
、d.items()
はlist(d.keys())
、list(d.values())
、list(d.items())
-
d.iterkeys()
、d.itervalues()
およびd.iteritems()
はiter(d.keys())
に変更するか、iter(d)
変更する必要があります。iter(d.values())
およびiter(d.items())
それぞれ - そして最終的にはPython 2.7メソッド呼び出し
d.viewkeys()
、d.viewvalues()
とd.viewitems()
で置き換えることができるd.keys()
d.values()
とd.items()
Python 2のコードを移植することは、辞書のキー、値、または項目を反復処理しながらそれを変更することは時々難しいことがあります。検討してください:
d = {'a': 0, 'b': 1, 'c': 2, '!': 3}
for key in d.keys():
if key.isalpha():
del d[key]
コードはPython 3でも同様に動作しkeys
が、 keys
メソッドはリストではなくビューオブジェクトを返します。繰り返し処理中に辞書のサイズが変更されると、Python 3のコードはRuntimeError: dictionary changed size during iteration
クラッシュしRuntimeError: dictionary changed size during iteration
。もちろん、解決策はfor key in list(d)
を正しく書き込むことfor key in list(d)
。
同様に、ビュー・オブジェクトはイテレータとは異なる動作をします。つまり、 next()
オブジェクトを使用することはできず、反復処理を再開することはできません。代わりに再起動します。 Python 2のコードがd.iterkeys()
、 d.itervalues()
またはd.iteritems()
の戻り値を、 iterableの代わりにiteratorを必要とするメソッドにd.iteritems()
場合、 iter(d)
、 iter(d.values())
Python 3ではiter(d.values())
またはiter(d.items())
します。
exec文はPython 3の関数です
Python 2では、 exec
は特別な構文を持つ文です: exec code [in globals[, locals]].
Python 3では、 exec
は関数exec(code, [, globals[, locals]])
になり、Python 2の構文はSyntaxError
ます。
print
がstatementから関数に変更されたときに、 __future__
importも追加されました。しかし、 from __future__ import exec_function
は必要ありませんfrom __future__ import exec_function
2のexec文は、Python 3のexec
関数の呼び出しとまったく同じ構文で使用することもできます。
exec 'code'
exec 'code' in global_vars
exec 'code' in global_vars, local_vars
フォームに
exec('code')
exec('code', global_vars)
exec('code', global_vars, local_vars)
後者の形式は、Python 2とPython 3の両方で同じように動作することが保証されています。
Python 2のhasattr関数のバグ
Python 2では、プロパティがエラーを発生させると、 hasattr
はこのプロパティを無視してFalse
返します。
class A(object):
@property
def get(self):
raise IOError
class B(object):
@property
def get(self):
return 'get in b'
a = A()
b = B()
print 'a hasattr get: ', hasattr(a, 'get')
# output False in Python 2 (fixed, True in Python 3)
print 'b hasattr get', hasattr(b, 'get')
# output True in Python 2 and Python 3
このバグはPython3で修正されています。したがって、Python 2を使用する場合は、
try:
a.get
except AttributeError:
print("no get property!")
代わりにgetattr
使用してください
p = getattr(a, "get", None)
if p is not None:
print(p)
else:
print("no get property!")
モジュール名の変更
標準ライブラリのいくつかのモジュールの名前が変更されました:
旧名 | 新しい名前 |
---|---|
_winreg | ウィグレッグ |
ConfigParser | configparser |
copy_reg | コピーレッグ |
キュー | キュー |
SocketServer | ソケットサーバー |
_markupbase | マークアップベース |
repr | reprlib |
test.test_support | test.support |
Tkinter | トキンター |
tkFileDialog | tkinter.filedialog |
urllib / urllib2 | urllib、urllib.parse、urllib.error、urllib.response、urllib.request、urllib.robotparser |
一部のモジュールは、ファイルからライブラリに変換さえさえあります。例として上からtkinterとurllibを取ってください。
互換性
Python 2.xと3.xの両方のバージョン間の互換性を維持する場合、 future
外部パッケージを使用して、Python 2.xバージョンでPython 3.xの名前を持つトップレベルの標準ライブラリパッケージをインポートすることができます。
オクタル定数
Python 2では、8進数のリテラルは次のように定義できます。
>>> 0755 # only Python 2
相互互換性を保証するには、
0o755 # both Python 2 and Python 3
すべてのクラスは、Python 3では「新しいスタイルのクラス」です。
Python 3.x
すべてのクラスは新しいスタイルのクラスです。新しいクラスを定義するとき、Pythonは暗黙的にobject
から継承しobject
。そのため、 class
定義でobject
を指定するobject
は完全にオプションです。
class X: pass
class Y(object): pass
これらのクラスはどちらも、 object
をmro
(メソッド解決順序)にmro
object
。
>>> X.__mro__
(__main__.X, object)
>>> Y.__mro__
(__main__.Y, object)
Python 2.x
クラスは、デフォルトで古いスタイルのクラスです。彼らは暗黙のうちにobject
から継承しません。これにより、基本class
としてobject
を明示的に追加するかどうかによって、クラスのセマンティクスが異なります。
class X: pass
class Y(object): pass
この場合、 Y
の__mro__
を出力しようとすると、Python 3.x
場合と同様の出力が表示されます:
>>> Y.__mro__
(<class '__main__.Y'>, <type 'object'>)
これは、明示的にY
をオブジェクトから継承させるために、 class Y(object): pass
定義するために発生します。オブジェクトから継承しないクラスX
場合、 __mro__
属性は存在しません。アクセスしようとするとAttributeError
ます。
両方のPythonバージョン間の互換性を保証するために、 object
を基本クラスとしてクラスを定義することができます。
class mycls(object):
"""I am fully compatible with Python 2/3"""
あるいは、 __metaclass__
変数がグローバルスコープでtype
に設定されている場合、 __metaclass__
されたモジュール内で後で定義されるすべてのクラスは、 object
から明示的に継承する必要がなく暗黙のうちに新しいスタイルになりobject
。
__metaclass__ = type
class mycls:
"""I am also fully compatible with Python 2/3"""
削除された演算子<>と! `は、!=とrepr()と同義です。
Python 2では、 <>
は!=
同義語です。同様に、 `foo`
はrepr(foo)
同義語です。
>>> 1 <> 2
True
>>> 1 <> 1
False
>>> foo = 'hello world'
>>> repr(foo)
"'hello world'"
>>> `foo`
"'hello world'"
>>> 1 <> 2
File "<stdin>", line 1
1 <> 2
^
SyntaxError: invalid syntax
>>> `foo`
File "<stdin>", line 1
`foo`
^
SyntaxError: invalid syntax
もはや利用可能な16進数へのエンコード/デコード
"1deadbeef3".decode('hex')
# Out: '\x1d\xea\xdb\xee\xf3'
'\x1d\xea\xdb\xee\xf3'.encode('hex')
# Out: 1deadbeef3
"1deadbeef3".decode('hex')
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# AttributeError: 'str' object has no attribute 'decode'
b"1deadbeef3".decode('hex')
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# LookupError: 'hex' is not a text encoding; use codecs.decode() to handle arbitrary codecs
'\x1d\xea\xdb\xee\xf3'.encode('hex')
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# LookupError: 'hex' is not a text encoding; use codecs.encode() to handle arbitrary codecs
b'\x1d\xea\xdb\xee\xf3'.encode('hex')
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# AttributeError: 'bytes' object has no attribute 'encode'
ただし、エラーメッセージで示唆されるように、 codecs
モジュールを使用して同じ結果を得ることができます。
import codecs
codecs.decode('1deadbeef4', 'hex')
# Out: b'\x1d\xea\xdb\xee\xf4'
codecs.encode(b'\x1d\xea\xdb\xee\xf4', 'hex')
# Out: b'1deadbeef4'
codecs.encode
はbytes
オブジェクトを返します。 ASCIIにdecode
するstr
オブジェクトを取得するには:
codecs.encode(b'\x1d\xea\xdb\xee\xff', 'hex').decode('ascii')
# Out: '1deadbeeff'
Python 3でcmp関数が削除されました
Python 3では、 cmp
組み込み関数が__cmp__
特殊メソッドとともに削除されました。
ドキュメントから:
cmp()
関数は__cmp__()
として扱われ、__cmp__()
特殊メソッドはサポートされなくなりました。ソートには__eq__()
、__hash__()
は__lt__()
を使用し、必要に応じて他の豊富な比較を使用します。 (実際にcmp()
機能が必要な場合は、式(a > b) - (a < b)
をcmp(a, b)
同等物として使用できます。
さらに、 cmp
パラメーターを受け入れた組み込み関数はすべて、 key
キーワードのみのパラメーターを受け入れるようになりました。
でfunctools
モジュールにも便利な機能がありcmp_to_key(func)
あなたから変換することができcmp
にスタイルのファンクションkey
スタイルの機能:
古いスタイルの比較関数をキー関数に変換します。キー機能(
sorted()
、min()
、max()
、heapq.nlargest()
、heapq.nsmallest()
、itertools.groupby()
)を受け付けるツールで使用されます。この関数は主に、比較関数の使用をサポートするPython 2から変換されるプログラムの遷移ツールとして使用されます。
リストの理解における漏れ変数
x = 'hello world!'
vowels = [x for x in 'AEIOU']
print (vowels)
# Out: ['A', 'E', 'I', 'O', 'U']
print(x)
# Out: 'U'
x = 'hello world!'
vowels = [x for x in 'AEIOU']
print (vowels)
# Out: ['A', 'E', 'I', 'O', 'U']
print(x)
# Out: 'hello world!'
この例からわかるように、Python 2ではx
の値が漏れました。それはhello world!
マスクしましたhello world!
これはループが終了したときのx
の最後の値だったので、 U
出力します。
しかし、Python 3 x
では、最初に定義されたhello world!
プリントされhello world!
リスト内包表記のローカル変数は、周囲のスコープの変数をマスクしないためです。
さらに、ジェネレータ表現(Python 2.5以降で利用可能)や、辞書や集合の補完(Python 3からPython 2.7にバックポートされた)はPython 2で変数をリークしません。
Python 2とPython 3の両方で、forループを使用すると、変数が周囲のスコープに漏れることに注意してください。
x = 'hello world!'
vowels = []
for x in 'AEIOU':
vowels.append(x)
print(x)
# Out: 'U'
地図()
map()
は、iterableの要素に関数を適用するのに便利な組み込み関数です。 Python 2では、 map
はリストを返します。 Python 3では、 map
はジェネレータであるマップオブジェクトを返します。
# Python 2.X
>>> map(str, [1, 2, 3, 4, 5])
['1', '2', '3', '4', '5']
>>> type(_)
>>> <class 'list'>
# Python 3.X
>>> map(str, [1, 2, 3, 4, 5])
<map object at 0x*>
>>> type(_)
<class 'map'>
# We need to apply map again because we "consumed" the previous map....
>>> map(str, [1, 2, 3, 4, 5])
>>> list(_)
['1', '2', '3', '4', '5']
Python 2では、 None
を渡してID関数として機能させることができます。これはもはやPython 3では機能しません。
>>> map(None, [0, 1, 2, 3, 0, 4])
[0, 1, 2, 3, 0, 4]
>>> list(map(None, [0, 1, 2, 3, 0, 5]))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not callable
さらに、Python 2で引数として複数のiterableを渡す場合、 map
は短いiterableをNone
( itertools.izip_longest
似ていitertools.izip_longest
)でitertools.izip_longest
ます。 Python 3では、反復は最短の反復可能性の後に停止します。
Python 2では:
>>> map(None, [1, 2, 3], [1, 2], [1, 2, 3, 4, 5])
[(1, 1, 1), (2, 2, 2), (3, None, 3), (None, None, 4), (None, None, 5)]
Python 3では:
>>> list(map(lambda x, y, z: (x, y, z), [1, 2, 3], [1, 2], [1, 2, 3, 4, 5]))
[(1, 1, 1), (2, 2, 2)]
# to obtain the same padding as in Python 2 use zip_longest from itertools
>>> import itertools
>>> list(itertools.zip_longest([1, 2, 3], [1, 2], [1, 2, 3, 4, 5]))
[(1, 1, 1), (2, 2, 2), (3, None, 3), (None, None, 4), (None, None, 5)]
注意 : map
代わりに、リスト内包表記(Python 2/3互換)を使用することを検討してください 。 map(str, [1, 2, 3, 4, 5])
置き換えmap(str, [1, 2, 3, 4, 5])
:
>>> [str(i) for i in [1, 2, 3, 4, 5]]
['1', '2', '3', '4', '5']
filter()、map()およびzip()はシーケンスの代わりにイテレータを返します
Python 3 filter
、代わりにmap
とzip
がイテレータを返します。
>>> it = filter(lambda x: x.isalpha(), 'a1b2c3')
>>> it
<filter object at 0x00000098A55C2518>
>>> ''.join(it)
'abc'
>>> it = map(lambda x: x * x, [0, 1, 2])
>>> it
<map object at 0x000000E0763C2D30>
>>> list(it)
[0, 1, 4]
>>> it = zip([0, 1, 2], [3, 4, 5])
>>> it
<zip object at 0x000000E0763C52C8>
>>> list(it)
[(0, 3), (1, 4), (2, 5)]
Python 2 itertools.izip
はPython 3と同等ですzip
izip
はPython 3で削除されています。
絶対/相対輸入
Python 3では、 PEP 404はPython 2からのインポートの仕方を変更します。 暗黙の相対インポートはパッケージやfrom ... import *
importsはモジュールレベルのコードでのみ許可されています。
Python 2でPython 3の動作を実現するには:
- 絶対インポート機能は
from __future__ import absolute_import
有効にすることができますfrom __future__ import absolute_import
- 明示的な相対輸入は、 暗黙の相対輸入の代わりに奨励される
明確にするために、Python 2では、モジュールは次のように同じディレクトリにある別のモジュールの内容をインポートできます:
import foo
foo
の場所は、import文だけではあいまいであることに注意してください。このような暗黙の相対インポートは、 明示的な相対インポートを優先して行います。次のようになります。
from .moduleY import spam
from .moduleY import spam as ham
from . import moduleY
from ..subpackage1 import moduleY
from ..subpackage2.moduleZ import eggs
from ..moduleA import foo
from ...package import bar
from ...sys import path
ドット.
ディレクトリツリー内のモジュール位置を明示的に宣言できます。
相対輸入の詳細
shapes
と呼ばれるユーザー定義のパッケージについて考えてみましょう。ディレクトリ構造は次のとおりです。
shapes
├── __init__.py
|
├── circle.py
|
├── square.py
|
└── triangle.py
circle.py
、 square.py
、およびtriangle.py
すべてモジュールとしてutil.py
をインポートします。同じレベルのモジュールをどのように参照するのでしょうか?
from . import util # use util.PI, util.sq(x), etc
または
from .util import * #use PI, sq(x), etc to call functions
.
同じレベルの相対的なインポートに使用されます。
次に、 shapes
モジュールの別のレイアウトを考えてみましょう。
shapes
├── __init__.py
|
├── circle
│ ├── __init__.py
│ └── circle.py
|
├── square
│ ├── __init__.py
│ └── square.py
|
├── triangle
│ ├── __init__.py
│ ├── triangle.py
|
└── util.py
さて、これらの3つのクラスはutil.pyをどのように参照しますか?
from .. import util # use util.PI, util.sq(x), etc
または
from ..util import * # use PI, sq(x), etc to call functions
..
は、親レベルの相対インポートに使用され..
。もっと追加してください.
親と子の間のレベルの数を持つ。
ファイルI / O
file
はもはや3.xの組み込みの名前ではありません(まだopen
います)。
ファイルI / Oの内部の詳細は、標準ライブラリio
モジュールに移されました。これはStringIO
新しいホームです。
import io
assert io.open is open # the builtin is an alias
buffer = io.StringIO()
buffer.write('hello, ') # returns number of characters written
buffer.write('world!\n')
buffer.getvalue() # 'hello, world!\n'
ファイルモード(テキスト対バイナリ)は、ファイルを読み込むことによって生成されるデータのタイプ(および書き込みに必要なタイプ)を決定するようになりました。
with open('data.txt') as f:
first_line = next(f)
assert type(first_line) is str
with open('data.bin', 'rb') as f:
first_kb = f.read(1024)
assert type(first_kb) is bytes
テキストファイルのエンコーディングは、デフォルトでlocale.getpreferredencoding(False)
によって返されるものになります。エンコードを明示的に指定するには、 encoding
キーワードパラメータを使用します。
with open('old_japanese_poetry.txt', 'shift_jis') as text:
haiku = text.read()
round()関数のタイブレークと戻り値の型
ラウンド()タイブレーク
Python 2では、2つの整数に等しく近い数にround()
を使用すると、0から最も遠いものが返されます。例:
round(1.5) # Out: 2.0
round(0.5) # Out: 1.0
round(-0.5) # Out: -1.0
round(-1.5) # Out: -2.0
しかし、Python 3では、 round()
は偶数の整数を返します(別名銀行家の丸め )。例えば:
round(1.5) # Out: 2
round(0.5) # Out: 0
round(-0.5) # Out: 0
round(-1.5) # Out: -2
ラウンド()関数は、以下の半分にも丸めに戦略その最も近い偶数の整数になりますが、ラウンド途中の番号(例えば、 round(2.5)
今2なく、3.0を返します)。
Wikipediaの参考文献によると 、これは不偏丸め 、 収束丸め 、 統計学者の丸め 、 オランダの丸め 、 ガウス丸め 、または奇数 - 偶数丸めとも呼ばれます 。
半分から偶数への丸めはIEEE 754標準の一部であり、Microsoftの.NETのデフォルトの丸めモードでもあります。
この丸め戦略は、丸め誤差の合計を減らす傾向があります。丸められた数値の量は平均して切り捨てられた数値の量と同じなので、丸め誤差はキャンセルされます。代わりに、他の丸め方法は、平均誤差に上方または下方バイアスを有する傾向がある。
round()戻り値の型
round()
関数は、Python 2.7でfloat
型を返します
round(4.8)
# 5.0
Python 3.0から、2番目の引数(桁数)を省略すると、 int
返します。
round(4.8)
# 5
真、偽、なし
Python 2ではTrue
、 False
、 None
は組み込み定数です。つまり、それらを再割り当てすることができます。
True, False = False, True
True # False
False # True
Python 2.4以降、これをNone
行うことはできません。
None = None # SyntaxError: cannot assign to None
Python 3では、 True
、 False
、 None
はキーワードになりました。
True, False = False, True # SyntaxError: can't assign to keyword
None = None # SyntaxError: can't assign to keyword
ファイルオブジェクトへの書き込み時の戻り値
Python 2では、ファイルハンドルに直接書き込むとNone
が返されます。
hi = sys.stdout.write('hello world\n')
# Out: hello world
type(hi)
# Out: <type 'NoneType'>
Python 3では、ハンドルに書き込むと、テキストを書き込むときに書き込まれる文字数と、バイトを書き込むときに書き込まれるバイト数が返されます。
import sys
char_count = sys.stdout.write('hello world 🐍\n')
# Out: hello world 🐍
char_count
# Out: 14
byte_count = sys.stdout.buffer.write(b'hello world \xf0\x9f\x90\x8d\n')
# Out: hello world 🐍
byte_count
# Out: 17
長い対int
Python 2では、C ssize_t
より大きい任意の整数が、リテラルにL
接尾辞で示されるlong
データ型に変換されます。たとえば、Pythonの32ビットビルドでは、次のようになります。
>>> 2**31
2147483648L
>>> type(2**31)
<type 'long'>
>>> 2**30
1073741824
>>> type(2**30)
<type 'int'>
>>> 2**31 - 1 # 2**31 is long and long - int is long
2147483647L
しかし、Python 3では、 long
データ型が削除されました。整数がどれほど大きくてもint
ます。
2**1024
# Output: 179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216
print(-(2**1024))
# Output: -179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216
type(2**1024)
# Output: <class 'int'>
クラスブール値
Python 2では、クラスのブール値を自分で定義する場合は、クラスに__nonzero__
メソッドを実装する必要があります。値はデフォルトでTrueです。
class MyClass:
def __nonzero__(self):
return False
my_instance = MyClass()
print bool(MyClass) # True
print bool(my_instance) # False
Python 3では、 __bool__
代わりに__nonzero__
が使用されています
class MyClass:
def __bool__(self):
return False
my_instance = MyClass()
print(bool(MyClass)) # True
print(bool(my_instance)) # False