Python3.12の新機能ハイライト
Python3.12の注目新機能
What’s new in Python 3.12を全部読むのは面倒だなと感じる人向けにオススメ機能を独断と偏見でリストアップ。
Type Parameter Syntax(イチオシ!)
モダンな型付き言語と同じ文法でジェネリクスをかけるようになります。
これまで
クラスや関数でGenericsを定義するためにはTypeVar
文法を使う必要がありました。クラス定義の際にはGenericを継承する必要がありました。さらにオプションでcovariantやboundを定義する文法はあまりクリーンではありませんでした。covarianceとかcontravarianceってなに?(英語)
from typing import Generic, TypeVar
_T_co = TypeVar("_T_co", covariant=True, bound=str)
class ClassA(Generic[_T_co]):
def method1(self) -> _T_co:
...
_T = TypeVar("_T")
def func(a: _T, b: _T) -> _T:
...
これから
JavaやRustでおなじみの文法でクリーンにジェネリクスを表現できるようになりました。
class ClassA[T: str]:
def method1(self) -> T:
...
def func[T](a: T, b: T) -> T:
...
GenericなTypeAliasを新文法type
で定義できます。
type ListOrSet[T] = list[T] | set[T]
float_list_or_set: ListOrSet[float] # valid
**kwargs
をアノテーションする
TypedDictでこれまで
これまでは**kwargs
は単一の型でアノテーションすることしかできませんでした。
def foo(*args: str, **kwds: int): ...
foo('a', 'b', 'c')
foo(x=1, y=2)
foo('', z=0)
またGenericなTypeAliasを定義することはできませんでした。
from typing import TypeAlias
_T = TypeVar("_T")
ListOrSet: TypeAlias = list[_T] | set[_T]
float_list_or_set: ListOrSet[float] # invalid
これから
kwargsをTypedDictで正確にアノテーションできるようになりました。
from typing import TypedDict, Unpack
class Movie(TypedDict):
name: str
year: int
def foo(**kwargs: Unpack[Movie]): ...
foo(name="hoge", year=3) # valid
foo(undefined_key=None) # invalid
Override Decorator
これまで
これまでPyrightなどの言語サーバーにとってサブクラスのメソッドが親クラスのメソッドをOverrideしてることを認識する方法はありませんでした。このため親クラスのメソッドの名前が変更されると本来サブクラスのメソッド名もかわるべきですが、言語サーバーにこれを検知する方法はありませんでした。
これから
from typing import override
class Base:
def get_color(self) -> str:
return "blue"
class GoodChild(Base):
@override # ok: overrides Base.get_color
def get_color(self) -> str:
return "yellow"
class BadChild(Base):
@override # type checker error: does not override Base.get_color
def get_colour(self) -> str:
return "red"
@override
デコレータを明示的にメソッドに付与することで、親クラスと整合性が取れないメソッド定義をエラーとして扱うようになります。
Nested f-string
これまで
f-stringの最大ネスト数(する必要ある?)は4でした。
f"""{f'''{f'{f"{1+1}"}'}'''}"""
これから
無限にネストできます。やったー。
f"{f"{f"{f"{f"{f"{1+1}"}"}"}"}"}"
Pathlibのちょい進化
これまで
".."を含む相対パスの計算はos.path.relpathではできましたが、pathlib.Path.relative_toではエラーになっていました。
parent = "./"
child = "./data"
print(os.path.relpath(child, parent)) # data
print(os.path.relpath(parent, child)) # ..
parent = Path("./")
child = Path("./data")
print(child.relative_to(parent)) # data
print(
parent.relative_to(child)
) # Value error '.' is not in the subpath of 'data' OR one path is relative and the other is absolute.
これから
os.path.relpathと一貫する形で親フォルダにもさかのぼることができます。
parent = "./"
child = "./data"
print(os.path.relpath(child, parent)) # data
print(os.path.relpath(parent, child)) # ..
parent = Path("./")
child = Path("./data")
print(child.relative_to(parent)) # data
print(parent.relative_to(child)) # ..
まとめ
タイプアノテーションかなり完成してきました。もうTypeScriptのように思った型を効率よく書く方法はほぼすべてそろってきたんじゃないでしょうか。OSSもpolarsのような新しいライブラリは当然のことPyTorchのような古いライブラリのサポートもかなり充実してきているとおもいます。
皆様も新規プロジェクトでは必ずタイプアノテーションをつけるようにしましょう。
Discussion