フリーキーズ | 独学プログラミング

Python 3.12.0がリリースされたので便利機能を触ってみる

最終更新日
【画像】Python 3.12.0がリリースされたので便利機能を触ってみる

2023年10月2日、Python 3.12.0がにリリースされました。毎年、10月に何かしらアップデートがされるPythonですが、今年も予定通りです。

Python 3.12.0にはいくつかの新機能や改善点が含まれており、このコンテンツではそれらの中からいくつかを紹介します。
すべての変更点を知りたい場合は、以下のリンクから追ってみてください。

紹介するPython 3.12.0の変更点

今回紹介する変更点は以下です。

  • 改良されたエラーメッセージ
  • 表現力が多彩になったf文字列
  • ジェネリクスを使う新しい型引数構文

触れないこと

  • distutilssmtpdが標準ライブラリから削除
  • ospathlibのファイルシステムサポートの向上
  • 速度向上
  • デコレータのオーバーライド
  • TypeDictによる**kwargsの型付け

エラーメッセージの改善

Pythonはもともと初心者向けの言語として認知されており、読みやすい構文が特徴の1つとされています。
今回のバージョンアップで、さらにユーザーフレンドリーになった機能の1つがエラーメッセージです。

Python 3.10では構文エラーがより正確になり、Python 3.11ではトレースバックによって問題のあるコードを特定するのがより快適になりました。

Python 3.12では、エラーメッセージを改良することで、開発者体験を向上させる努力が続けられています。

まず、インポートエラーから紹介します。以下のコードをインタプリタやPythonファイルから実行してみましょう。

glob.glob('*')

これは以下のエラーを出力します。

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のインポートを忘れていないかを聞いてくれます。

インポート忘れのリマインダーは標準ライブラリモジュールに対してのみ発生します。プロジェクトにインストールしたサードパーティモジュールには発生しません。

次に、構文エラーに近しいですが、インポート時の別エラーメッセージについて紹介します。
以下を書いてみましょう。

import search from re

以下のように出力されます。

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から始める必要があることを教えてくれます。
さらに、以下のケースでも改良されています。

from re import searc

あえてsearchsearcとタイポしています。これは以下のように出力されます。

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系に注目していきたいところです。

関連するコンテンツ