2023年10月2日、Python 3.12.0がにリリースされました。毎年、10月に何かしらアップデートがされるPythonですが、今年も予定通りです。
Python 3.12.0にはいくつかの新機能や改善点が含まれており、このコンテンツではそれらの中からいくつかを紹介します。
すべての変更点を知りたい場合は、以下のリンクから追ってみてください。
紹介するPython 3.12.0の変更点
今回紹介する変更点は以下です。
改良されたエラーメッセージ
表現力が多彩になったf
文字列
ジェネリクスを使う新しい型引数構文
触れないこと
distutils
、smtpd
が標準ライブラリから削除
os
、pathlib
のファイルシステムサポートの向上
速度向上
デコレータのオーバーライド
TypeDictによる**kwargs
の型付け
エラーメッセージの改善
Pythonはもともと初心者向けの言語として認知されており、読みやすい構文が特徴の1つとされています。
今回のバージョンアップで、さらにユーザーフレンドリーになった機能の1つがエラーメッセージです。
Python 3.10では構文エラーがより正確になり、Python 3.11ではトレースバックによって問題のあるコードを特定するのがより快適になりました。
Python 3.12では、エラーメッセージを改良することで、開発者体験を向上させる努力が続けられています。
まず、インポートエラーから紹介します。以下のコードをインタプリタやPythonファイルから実行してみましょう。
これは以下のエラーを出力します。
Traceback ( most recent call last ) :
File "<stdin>" , line 1 , in < module >
NameError: name 'glob' is not defined. Did you forget to import 'glob' ?
glob
をインポートせずに使用すると従来と同じくNameError
が発生しますが、さらに追加でglob
のインポートを忘れていないかを聞いてくれます。
インポート忘れのリマインダーは標準ライブラリモジュールに対してのみ発生します。プロジェクトにインストールしたサードパーティモジュールには発生しません。
次に、構文エラーに近しいですが、インポート時の別エラーメッセージについて紹介します。
以下を書いてみましょう。
以下のように出力されます。
Traceback ( most recent call last ) :
File "<stdin>" , line 1
import search from re
^^^^^^^^^^^^^^^^^^^^^
SyntaxError: Did you mean to use 'from ... import ...' instead?
TypeScriptなどと違って、Pythonではfrom
から始める必要があることを教えてくれます。
さらに、以下のケースでも改良されています。
あえてsearch
をsearc
とタイポしています。これは以下のように出力されます。
Traceback ( most recent call last ) :
File "<stdin>" , line 1 , in < module >
ImportError: cannot import name 'searc' from 're' ( /Users/kt2763/.pyenv/versions/3.12.0/lib/python3.12/re/__init__.py ) . Did you mean: 'search' ?
限定的ではありますが、簡単なタイポであれば検出できるようになっています。
最後にクラス内で定義したインスタンス変数についてのエラーメッセージです。以下のようなクラスを書いてみましょう。
class Sample :
def __init__ ( self , name ) :
self . name = name
def say_hello ( self ) :
return f'Hello, { name } '
s = Sample ( 'Taro' )
print ( s . say_hello ( ) )
これは以下のようなエラーメッセージを出力します。
Traceback ( most recent call last ) :
File "sample.py" , line 9 , in < module >
print ( s.say_hello ( ))
^^^^^^^^^^^^^
File "sample.py" , line 6 , in say_hello
return f 'Hello, {name}'
^^^^
NameError: name 'name' is not defined. Did you mean: 'self.name' ?
インスタンス変数にname
が存在することを解釈し、name
の代わりにself.name
を提案してくれます。
問題点が改善されたf
文字列
書式付き文字列、略してf
文字列はPEP498とPython 3.6で導入されました。以下のようなコードであれば、特に今回のアップデートにおける改善は関係なく使えます。
name = 'Taro'
print ( f'Hello, { name } !' )
ただし、今までのf
文字列には問題点がありました。""
(ダブルクォーテーション)で""
(ダブルクォーテーション)は囲めないのです。
たとえば、以下のコードではエラーが出ます。
fruit_colors = { "banana" : "yellow" , "cherry" : "red" }
print ( f"Banana is {fruit_colors[" banana "]}" )
File "sample.py" , line 2
print ( f "Banana is {fruit_colors[" banana "]}" )
^^^^^^
SyntaxError: f-string: unmatched '['
\
(バックスラッシュ)を使っても解決できません。
fruit_colors = { "banana" : "yellow" , "cherry" : "red" }
print ( f"Banana is { fruit_colors [ \"banana\" ] } " )
File "sample.py" , line 2
print ( f "Banana is {fruit_colors[ \" banana \" ]}" )
^
SyntaxError: f-string expression part cannot include a backslash
Pyhton 3.12.0では、f
文字列内で""
を使えるようになりました。
fruit_colors = { "banana" : "yellow" , "cherry" : "red" }
print ( f"Banana is {fruit_colors[" banana "]}" )
# 出力 Banana is yellow
また、これまではf
文字列の中で\
(バックスラッシュ)を使用できませんでした。3.12.0からは、f
文字列でもバックスラッシュを使用できます。
fruits = [ "banana" , "apple" , "orange" ]
print ( f"Fruits list\n{" \n ".join(fruits)}" )
# 出力
# Fruits list
# banana
# apple
# orange
さらに中括弧内の改行にも対応しており、コメントも追加できます。
fruits = [ "banana" , "apple" , "orange" ]
print ( f"Fruits list \n {
"\n" . join ( fruits )
# This is fruits list
} " )
これによって、変数展開を必要とする長めの文字列を作成する際、とても便利になりました。
専用の型引数構文
Pythonはバージョン3.0で関数アノテーションをサポートしました。その後、Python 3.5から静的型付けをサポートするようになりました。
型引数はPythonの型付けシステムの重要で強力な部分を構成しています。
型引数は、静的型チェックの際に具体的な型の代わりとなります。型引数は、ジェネリッククラスやジェネリック関数をパラメータ化するために使います。次の例では、与えられたリストの最初の要素を返します。
def get_head ( params ) :
return params [ 0 ]
get_head()
の返り値の型は、渡すリストに依存しています。例えば、params
が整数のリストならget_head()
はint
を返し、文字列のリストならstr
を返します。
この関係性を表現するために型変数を使います。
Python 3.12では型引数の新しい構文が導入されました。新しい構文を使うと、次のように書けます。
def get_head [ T ] ( params : list [ T ] ) - > T :
return params [ 0 ]
関数定義に角括弧でT
を追加することで、get_head()
が型変数T
をパラメータとする汎用関数であることを宣言しています。
このように、より厳密なコーディングをサポートしているため、Pythonで弱点だった(弱点とされていた)動的型付けをまた一歩改善しています。
Python 3.12.0は細かな気配りアップデート
Python 3.12.0では、抜本的な改革こそありませんが、逆に言えば破壊的な変更もありませんでした。
成熟したプログラミング言語として、より精密かつ細かなところに手が届きやすいプログラミング言語としての進展と言えるでしょう。
Pythonはプログラミング初心者から熟練者まで使う言語であることから、シンプルな構文を捨てることなく、こういったより練度の高い方法で書けるのはありがたいことです。
まだライブラリのサポート等が追いついていないケースもありますが、今後のPython 3.12.x系に注目していきたいところです。