web-dev-qa-db-fra.com

Comment créer une fonction composer

J'essaie de créer une fonction qui complète d'autres fonctions pour mon diplôme universitaire. Par exemple, je voudrais appeler la round_sqrt = round(sqrt) et quand j'appelle la round_sqrt(5) elle doit me montrer 2 Au lieu de 2.23606797749979. Ce que j'essaie, c'est ceci:

def rounding(funct):
    return round(funct)

mais cela ne fonctionne pas.

EDIT: La fonction ne doit avoir qu'un seul paramètre. Par exemple, le début de la fonction doit être

def rounding(func):

donc dans cette fonction, la fonction funct doit être arrondie. donc quand j'appelle rounding(abs)(3.2) il me montre 3.

19
php kubrick

Pour votre exemple spécifique, vous pouvez écrire

def round_sqrt(x):
    return round(sqrt(x))

réponse d'Alex généralise cela; il définit une fonction qui crée round_sqrt pour vous. Si la fonction est déjà définie, il vous suffit de la passer comme argument à rounder:

round_sqrt = rounder(sqrt)

Bien sûr, vous n'avez pas besoin de définir round_sqrt Si vous ne le souhaitez pas. rounder(sqrt)(3.2) peut être appelée directement, bien qu'il soit beaucoup plus efficace de sécuriser la valeur de retour de rounder si vous prévoyez de l'utiliser plusieurs fois, plutôt que de la redéfinir à chaque fois.

Sinon, la syntaxe du décorateur est juste courte (en utilisant l'exemple d'Alex)

def adder(x, y):
    return x + y

adder = rounder(adder)

Comme je l'ai dit dans mon commentaire, il s'agit d'un exemple de mise en œuvre de la composition. Mathématiquement, la composition est simple, car les fonctions mathématiques prennent toujours un seul argument et renvoient un seul argument. Ainsi, la composition de deux fonctions f et g pourrait toujours être définie simplement comme

def compose(f, g):
    def h(x):   # The name doesn't matter
        return f(g(x))
    return h

Alors

round_sqrt = compose(round, sqrt)

(Ignorant toutes sortes de problèmes pratiques concernant l'implémentation, Python pourrait en théorie même fournir un opérateur Unicode Pour les fonctions: round_sqrt = round ∘ sort. Explication pourquoi cela ne se produira pas dépasse le cadre de cette réponse.)

En Python, cependant, les fonctions sont beaucoup plus compliquées. Ils peuvent prendre plusieurs arguments, ils peuvent accepter un nombre arbitraire d'arguments et d'arguments de mots-clés arbitraires, et bien que chacun renvoie techniquement une seule valeur, cette valeur peut être un tuple considéré comme plusieurs valeurs ou un dict. Par conséquent, vous pouvez vous attendre à plusieurs façons de passer la valeur de retour de g à une fonction f, plus que ce qui peut être facilement hébergé dans une simple fonction compose .

15
chepner

Vous devriez vérifier les fermetures:

def rounder(func):
    def inner(*args, **kwargs):
        return round(func(*args, **kwargs))
    return inner

Ensuite, vous pouvez décorer des fonctions en utilisant le @ personnage:

@rounder
def adder(x, y):
    return x + y

print(adder(1.1, 2.2))

les sorties 3

Supplémentaire:

  1. Vous pouvez utiliser functools.wraps dans votre fermeture afin de ne pas perdre d'informations (par exemple docstring, nom de la fonction) sur la fonction d'origine.
  2. Il existe un tas de ressources pour en savoir plus sur les fermetures (par exemple 1 , 2 ) et les décorateurs (par exemple 1 , 2 =) que vous pouvez trouver en recherchant ces termes sur Google.
27
Alex

La composition des fonctions n'est pas prise en charge nativement en Python. Vous pouvez utiliser un décorateur selon @ la solution d'Alex . Vous pouvez définir une nouvelle fonction explicitement selon @ solution de chepner .

Ou vous pouvez utiliser une bibliothèque tierce. Par exemple, via toolz.compose :

from toolz import compose

def adder(x, y):
    return x + y

round_adder = compose(round, adder)

round_adder(1.1, 2.2)  # 3
5
jpp