Maison  >  Article  >  développement back-end  >  Surcharge de fonctions en Python

Surcharge de fonctions en Python

DDD
DDDoriginal
2024-09-24 06:24:45672parcourir

Overloading functions in Python

La surcharge de fonctions fait référence à la possibilité de définir plusieurs fonctions avec le même nom mais des signatures différentes, ce qui signifie qu'elles ont des nombres ou des types de paramètres différents. La version correcte de la fonction est choisie automatiquement par le compilateur ou l'interpréteur, en fonction du nombre et du type d'arguments passés lors de l'appel de la fonction.

Des langages comme Java et C++ prennent en charge cette fonctionnalité de manière native.

Bien que Python ne prenne pas en charge la surcharge de fonctions de manière native puisqu'il s'agit d'un langage typé dynamiquement, il est possible de l'implémenter à l'aide de divers modules et utilitaires.

C'est mon implémentation de la surcharge.

Mise en œuvre

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

La classe OverloadNamespace est un appelable qui agit comme un intermédiaire entre le nom de la fonction et la signature de l'appel. Les arguments sont transmis à la méthode __call__ dunder qui fait correspondre les types de données fournis avec les tuples de types stockés dans le dictionnaire des surcharges. La signature correspondante est renvoyée et est appelée avec les arguments/kwargs fournis. Si aucune signature correspondante n'est trouvée, la fonction de secours est appelée.

Utilisation de la classe OverloadNamespace

Cette classe n'est pas destinée à être utilisée manuellement, elle est utilisée par des décorateurs qui modifient la fonction et renvoient une instance de la classe OverloadNamespace en utilisant le même nom que le nom fourni par la fonction.

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

Le décorateur de surcharge vérifie les types d'arguments à l'aide de la valeur du décorateur ou des indices de type et renvoie la classe d'espace de noms.

Exemple d'utilisation

# 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

Ceci n'est qu'une idée de base et fonctionne pour les types fixes non syndiqués.

Retomber

Les fonctions de secours sont utilisées comme fonction à appeler lorsqu'aucun modèle d'argument ne correspond au modèle d'appel.

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

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn