SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Pythonの新機能を知ろう!

【Python 3.12への道のり】3.11で導入された可変長ジェネリクス・データクラス変換とは?型関連の機能を紹介

Pythonの新機能を知ろう! 第2回

ジェネリクスのおさらいと型変数タプル

 Python 3.11では、tuple[*Ts]というような型ヒントにより、可変長の引数にジェネリクスの利用が可能になりました。これは型変数タプルTypeVarTupleで実現されます。

ジェネリクスとは?

 型変数タプルを紹介するにあたり、まずはジェネリクスについておさらいしておきます。ジェネリクスは、JavaやC#などのプログラミング言語でおなじみの機能ですが、Pythonでは型変数TypeVarを使った型ヒントをジェネリクスと呼びます。ジェネリクスを使うことで、特定の型を明示的に指定するのではなく、実際の引数に応じて変化する汎用的な型ヒントを指定できます。例えば以下のリストは、任意の型の引数xから2要素のタプルを生成して返す関数make_tupleを定義しています。

リスト generics.py
from typing import TypeVar

# ジェネリックな型変数Tを定義
T = TypeVar("T")		(1)

# x: Tをタプルにして返す関数
def make_tuple(x: T) -> tuple[T, T]:
    return (x, x)

value_int = make_tuple(100) 		(2)
value_str = make_tuple('Hello')
print(value_int, value_str)	# 実行結果:(100, 100) ('Hello', 'Hello')

 (1)で型ヒントに与えられているTは、TypeVarによる型変数です。(2)の関数呼び出しではxの型(intおよびstr)がTに入ります。これにより、戻り値であるタプルの各要素の型もintあるいはstrになります。Pythonでは、このようにして関数の汎用化であるジェネリクスが実現されています。

型変数タプル

 しかしながら、型変数には1個の型しか代入できないので、例えば複数の異なる型からなるタプルを引数として渡す関数をジェネリクスで定義することはできません。そこでPython 3.11では、型変数タプルTypeVarTupleが導入されました。TypeVarTupleを使うと、複数の型を持てる型変数を定義できるので、これにより以下のリストのような関数定義が可能になります。

リスト var_generics.py
from typing import TypeVarTuple

# 型変数タプルを定義
Ts = TypeVarTuple("Ts")		(1)

# タプルに長さを加えて返す関数
def add_tuple_count(x: tuple[*Ts]) -> tuple[*Ts, int]:		(2)
    return (*x, len(x))

value = add_tuple_count(('Hello', 100)) 
print(value)					# 実行結果:('Hello', 100, 2)

 (1)のTsは、TypeVarTupleによって複数の型を収納できる型変数です。(2)のように、関数の引数は*Tsによる型ヒントとなっており、複数の型によるタプルを受け入れることになります。戻り値も同様の型ヒントとなり、末尾は必ずintになります。

静的型チェックツールの実行結果

 このリストはPylanceによるチェックでは問題になりませんが、mypyによるチェックで「"TypeVarTuple" support is experimental」「Invalid type comment or annotation」などのエラーになります。本稿作成時点のmypyでは型変数タプルのサポートが完全でないためと思われます。--enable-incomplete-feature=TypeVarTupleオプションの指定でもエラーは解消されない点に注意してください。

定義されているクラスを表す型変数Selfが使用可能に

 Python 3.11では、クラスの関数の戻り値が自分自身であることを示す型変数Selfが利用可能になりました。Python 3.10までは、以下のようにtyping.TypeVarを使って疑似的にSelf型を実現していたので、非常にシンプルになりました。

リスト self_1.py
from typing import TypeVar

# 上界にMyClassを指定した型変数Selfを宣言
Self = TypeVar("Self", bound="MyClass")		(1)

class MyClass:
    x: int
    # 自身を返すreturn_myself関数
    def return_myself(self: Self) -> Self:	(2)
      return self

c = MyClass()
c.return_myself().x = 1		# Selfを介してフィールドに値を設定
print(c.x)			# 実行結果:1

 (1)のTypeVarにより、SelfはMyClassのサブクラスという型変数になります。(2)では、MyClassクラスにおいて、return_myselfメソッドは自分自身を受け取って自分自身を返す関数として定義されています。TypeVarから型変数を生成する必要があるなどやや冗長ということで、Python 3.11では以下のように記述することができるようになりました。

リスト self_2.py
from typing_extensions import Self		(1)

# 型変数の宣言は不要

class MyClass:
    x: int
    def return_myself(self: Self) -> Self:
      return self

 クラスと関数の定義はそのままで、(1)のようにSelfのためのimport文を変更します。TypeVarによる型変数の定義がなくなることで、だいぶスッキリしますね。

次のページ
TypedDictのおさらいとRequired/NotRequired

この記事は参考になりましたか?

Pythonの新機能を知ろう!連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト 山内 直(WINGSプロジェクト ヤマウチ ナオ)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。 2026年時点での登録メンバは約50名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook <個人紹介>WINGSプロジェクト所属のテクニカルライター。出版社を経てフリーランスとして独立。ライター、エディター、デベロッパー、講師業に従事。屋号は「たまデジ。」。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるLaravel実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/18532 2023/10/31 11:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー