関数のオーバーロードとは、名前は同じだがシグネチャが異なる複数の関数を定義する機能を指します。つまり、関数のパラメーターの数や型が異なります。関数の正しいバージョンは、関数呼び出し中に渡される引数の数と型に応じて、コンパイラーまたはインタープリターによって自動的に選択されます。
Java や C++ などの言語は、これを機能としてネイティブにサポートしています。
Python は動的に型付けされた言語であるため、関数のオーバーロードをネイティブにサポートしていませんが、さまざまなモジュールやユーティリティを使用して同じものを実装することは可能です。
これは私によるオーバーロードの実装です。
from __future__ import annotations import inspect import typing bin: dict[str, OverloadNamespace] = {} class OverloadNamespace: overloads: dict[tuple[type, ...], typing.Callable[..., typing.Any]] fallback: typing.Callable[..., typing.Any] def __init__(self, name: str) -> None: self.overloads = {} self.fallback = self._fallback bin[name] = self def __call__(self, *args: typing.Any, **kwds: typing.Any) -> typing.Any: types = [type(arg) for arg in args] types.extend([type(kwrg) for kwrg in kwds]) try: return self.overloads[tuple(types)](*args, **kwds) except KeyError: return self.fallback(*args, **kwds) @staticmethod def _fallback(*_, **__) -> None: raise NotImplementedError
OverloadNamespace クラスは、関数名と呼び出し署名の間の媒体として機能する呼び出し可能クラスです。引数は __call__ dunder メソッドに渡され、指定されたデータ型とオーバーロード ディクショナリに格納されている型タプルを照合します。一致した署名が返され、指定された引数/kwargs を使用して呼び出されます。一致する署名が見つからない場合は、フォールバック関数が呼び出されます。
このクラスは手動で使用することを意図したものではなく、関数を変更し、関数の指定された名前と同じ名前を使用して OverloadNamespace クラスのインスタンスを返すデコレータによって利用されます。
def overload(*args) -> typing.Callable[..., OverloadNamespace] | OverloadNamespace: """Decorator used to create overloads of functions with same name. Returns a [OverloadNamespace]""" if len(args) == 1 and inspect.isfunction(args[0]): return overload_using_types(args[0]) def inner(func: typing.Callable[..., typing.Any]) -> OverloadNamespace: sig = inspect.signature(func) assert len(args) == len( sig.parameters ), "Number of types and args in function is not same." namespace = ( bin[func.__name__] if bin.get(func.__name__) else OverloadNamespace(func.__name__) ) namespace.overloads[tuple(args)] = func return namespace return inner def overload_using_types(func: typing.Callable[..., typing.Any]) -> OverloadNamespace: args = inspect.signature(func).parameters types = tuple(arg.annotation for arg in args.values()) namespace = ( bin[func.__name__] if bin.get(func.__name__) else OverloadNamespace(func.__name__) ) namespace.overloads[types] = func return namespace
オーバーロード デコレータは、デコレータ値またはタイプヒントを使用して引数の型をチェックし、名前空間クラスを返します。
使用例
# types in decorator @overload(int, int) def sum(a, b): return a+b # or as typehints @overload def sum(a: float, b: float): return int(a+b)+1 sum(1,2) # 3 sum(1.23, 2.0) # 4
これは単なる基本的な考え方であり、非共用体固定タイプに機能します。
フォールバック関数は、呼び出しパターンに一致する引数パターンがない場合に呼び出される関数として使用されます。
def fallback( func: typing.Callable[..., typing.Any], ) -> OverloadNamespace: """Fallback function to be called if no overloads match to the provided arguments.""" namespace = ( bin[func.__name__] if bin.get(func.__name__) else OverloadNamespace(func.__name__) ) namespace.fallback = func return namespace @fallback def sum(*args): return sum(args) sum(1,2,3,4) # 10
以上がPython での関数のオーバーロードの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。