Python での関数のオーバーロード

DDD
リリース: 2024-09-24 06:24:45
オリジナル
729 人が閲覧しました

Overloading functions in Python

関数のオーバーロードとは、名前は同じだがシグネチャが異なる複数の関数を定義する機能を指します。つまり、関数のパラメーターの数や型が異なります。関数の正しいバージョンは、関数呼び出し中に渡される引数の数と型に応じて、コンパイラーまたはインタープリターによって自動的に選択されます。

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 クラスの使用

このクラスは手動で使用することを意図したものではなく、関数を変更し、関数の指定された名前と同じ名前を使用して 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 サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート