Recherche…


Introduction

Les fonctions en Python fournissent un code organisé, réutilisable et modulaire pour effectuer un ensemble d'actions spécifiques. Les fonctions simplifient le processus de codage, empêchent la logique redondante et facilitent le suivi du code. Cette rubrique décrit la déclaration et l'utilisation des fonctions dans Python.

Python possède de nombreuses fonctions intégrées telles que print() , input() , len() . Outre les fonctions intégrées, vous pouvez également créer vos propres fonctions pour effectuer des tâches plus spécifiques, appelées fonctions définies par l'utilisateur .

Syntaxe

  • def nom_fonction (arg1, ... argN, * args, kw1, Kw2 = défaut, ..., ** kwargs): déclarations
  • lambda arg1, ... argN, * args, kw1, kw2 = par défaut, ..., ** kwargs : expression

Paramètres

Paramètre Détails
arg1 , ..., argN Arguments réguliers
* args Arguments de position sans nom
kw1 , ..., kwN Arguments uniquement liés aux mots clés
** kwargs Le reste des arguments de mots clés

Remarques

5 choses de base que vous pouvez faire avec les fonctions:

  • Assigner des fonctions à des variables

    def f():
      print(20)
    y = f
    y()
    # Output: 20
    
  • Définir des fonctions dans d'autres fonctions ( fonctions imbriquées )

    def f(a, b, y):
        def inner_add(a, b):      # inner_add is hidden from outer code
            return a + b
        return inner_add(a, b)**y
    
  • Les fonctions peuvent renvoyer d'autres fonctions

    def f(y):
        def nth_power(x):
            return x ** y
        return nth_power    # returns a function
    
    squareOf = f(2)         # function that returns the square of a number           
    cubeOf = f(3)           # function that returns the cube of a number
    squareOf(3)             # Output: 9
    cubeOf(2)               # Output: 8
    
  • Les fonctions peuvent être transmises comme paramètres à d'autres fonctions

    def a(x, y):
        print(x, y)
    def b(fun, str):        # b has two arguments: a function and a string 
        fun('Hello', str)
    b(a, 'Sophia')           # Output: Hello Sophia
    
  • Les fonctions internes ont accès à la portée englobante ( fermeture )

    def outer_fun(name):
        def inner_fun():     # the variable name is available to the inner function
            return "Hello "+ name + "!"
        return inner_fun
    greet = outer_fun("Sophia")
    print(greet())            # Output: Hello Sophia!
    

Ressources additionnelles

Définir et appeler des fonctions simples

L'utilisation de l'instruction def est le moyen le plus courant de définir une fonction en python. Cette instruction est une instruction composée d'une clause unique avec la syntaxe suivante:

def function_name(parameters):
    statement(s)

function_name est appelé identificateur de la fonction. Comme une définition de fonction est une instruction exécutable, son exécution lie le nom de la fonction à l'objet fonction qui peut être appelé ultérieurement à l'aide de l'identificateur.

parameters est une liste facultative d'identifiants qui sont liés aux valeurs fournies en tant qu'arguments lorsque la fonction est appelée. Une fonction peut avoir un nombre arbitraire d'arguments séparés par des virgules.

statement(s) - également appelée corps de la fonction - est une séquence non vide d'instructions exécutée à chaque appel de la fonction. Cela signifie qu'un corps de fonction ne peut pas être vide, comme n'importe quel bloc en retrait .

Voici un exemple de définition de fonction simple dont le but est d’imprimer Hello chaque fois qu’elle est appelée:

def greet():
    print("Hello")

Appelons maintenant la fonction greet() définie:

greet()
# Out: Hello

C'est un autre exemple de définition de fonction qui prend un seul argument et affiche la valeur passée à chaque fois que la fonction est appelée:

def greet_two(greeting):
    print(greeting)

Après cela, la fonction greet_two() doit être appelée avec un argument:

greet_two("Howdy")
# Out: Howdy

Vous pouvez également donner une valeur par défaut à cet argument de fonction:

def greet_two(greeting="Howdy"):
    print(greeting)

Maintenant, vous pouvez appeler la fonction sans donner de valeur:

greet_two()
# Out: Howdy 

Vous remarquerez que contrairement à de nombreux autres langages, vous n'avez pas besoin de déclarer explicitement un type de retour de la fonction. Les fonctions Python peuvent renvoyer des valeurs de tout type via le mot-clé return . Une fonction peut retourner n'importe quel nombre de types différents!

def many_types(x):
    if x < 0:
        return "Hello!"
    else:
        return 0

print(many_types(1))
print(many_types(-1))

# Output:
0
Hello!

Tant que cela est géré correctement par l'appelant, il s'agit d'un code Python parfaitement valide.

Une fonction qui arrive à la fin de l'exécution sans instruction de retour renverra toujours None :

def do_nothing():
    pass

print(do_nothing())
# Out: None

Comme mentionné précédemment, une définition de fonction doit avoir un corps de fonction, une séquence d'instructions non vide. Par conséquent, l'instruction pass est utilisée comme corps de fonction, ce qui est une opération null - quand il est exécuté, rien ne se produit. Il fait ce que cela signifie, il saute. Il est utile en tant qu'espace réservé lorsqu'une instruction est requise sur le plan syntaxique, mais aucun code ne doit être exécuté.

Renvoyer des valeurs de fonctions

Les fonctions peuvent return une valeur que vous pouvez utiliser directement:

def give_me_five():
    return 5

print(give_me_five())  # Print the returned value
# Out: 5

ou enregistrer la valeur pour une utilisation ultérieure:

num = give_me_five()
print(num)             # Print the saved returned value
# Out: 5

ou utilisez la valeur pour toutes les opérations:

print(give_me_five() + 10)
# Out: 15

Si le return est rencontré dans la fonction, la fonction sera immédiatement fermée et les opérations suivantes ne seront pas évaluées:

def give_me_another_five():
    return 5
    print('This statement will not be printed. Ever.')

print(give_me_another_five())
# Out: 5

Vous pouvez également return plusieurs valeurs (sous la forme d'un tuple):

def give_me_two_fives():
    return 5, 5  # Returns two 5

first, second = give_me_two_fives()
print(first)
# Out: 5
print(second)
# Out: 5

Une fonction sans instruction return renvoie implicitement None . De même, une fonction avec une déclaration de return , mais aucune valeur de retour ou variable ne renvoie None .

Définir une fonction avec des arguments

Les arguments sont définis entre parenthèses après le nom de la fonction:

def divide(dividend, divisor):  # The names of the function and its arguments
    # The arguments are available by name in the body of the function
    print(dividend / divisor)

Le nom de la fonction et sa liste d'arguments sont appelés la signature de la fonction. Chaque argument nommé est effectivement une variable locale de la fonction.

Lors de l'appel de la fonction, donnez des valeurs aux arguments en les listant dans l'ordre

divide(10, 2)
# output: 5

ou spécifiez-les dans n'importe quel ordre en utilisant les noms de la définition de fonction:

divide(divisor=2, dividend=10)
# output: 5

Définir une fonction avec des arguments facultatifs

Les arguments facultatifs peuvent être définis en attribuant (en utilisant = ) une valeur par défaut au nom de l'argument:

def make(action='nothing'):
    return action

L'appel de cette fonction est possible de 3 manières différentes:

make("fun")
# Out: fun

make(action="sleep")
# Out: sleep

# The argument is optional so the function will use the default value if the argument is 
# not passed in.
make()   
# Out: nothing

Attention

Les types Mutable ( list , dict , set , etc.) doivent être traités avec soin lorsqu'ils sont donnés en tant qu'attribut par défaut . Toute mutation de l'argument par défaut le changera de manière permanente. Voir Définition d'une fonction avec des arguments facultatifs mutables .

Définir une fonction avec plusieurs arguments

On peut donner à une fonction autant d'arguments que l'on veut, les seules règles fixes sont que chaque nom d'argument doit être unique et que les arguments optionnels doivent être après les non-optionnels:

def func(value1, value2, optionalvalue=10):
    return '{0} {1} {2}'.format(value1, value2, optionalvalue1)

Lorsque vous appelez la fonction, vous pouvez soit donner chaque mot-clé sans le nom, mais l'ordre compte:

print(func(1, 'a', 100))
# Out: 1 a 100

print(func('abc', 14))
# abc 14 10

Ou combiner en donnant les arguments avec nom et sans. Alors ceux avec nom doivent suivre ceux sans, mais l'ordre de ceux avec nom n'a pas d'importance:

print(func('This', optionalvalue='StackOverflow Documentation', value2='is'))
# Out: This is StackOverflow Documentation

Définir une fonction avec un nombre arbitraire d'arguments

Nombre arbitraire d'arguments de position:

Définir une fonction capable de prendre un nombre arbitraire d’arguments peut être fait en préfixant l’un des arguments avec un *

def func(*args):
    # args will be a tuple containing all values that are passed in
    for i in args:
        print(i)

func(1, 2, 3)  # Calling it with 3 arguments
# Out: 1
#      2
#      3

list_of_arg_values = [1, 2, 3]
func(*list_of_arg_values)  # Calling it with list of values, * expands the list
# Out: 1
#      2
#      3 

func()  # Calling it without arguments
# No Output 

Vous ne pouvez pas fournir une valeur par défaut pour args , par exemple func(*args=[1, 2, 3]) générera une erreur de syntaxe (ne compilera même pas).

Vous ne pouvez pas les fournir par nom lorsque vous appelez la fonction, par exemple func(*args=[1, 2, 3]) TypeError une TypeError .

Mais si vous avez déjà vos arguments dans un tableau (ou tout autre Iterable ), vous pouvez appeler votre fonction comme ceci: func(*my_stuff) .

Ces arguments ( *args ) sont accessibles par index, par exemple args[0] renverra le premier argument

Nombre arbitraire d'arguments de mot clé

Vous pouvez prendre un nombre arbitraire d'arguments avec un nom en définissant un argument dans la définition avec deux * devant lui:

def func(**kwargs):
    # kwargs will be a dictionary containing the names as keys and the values as values
    for name, value in kwargs.items():
        print(name, value)

func(value1=1, value2=2, value3=3)   # Calling it with 3 arguments
# Out: value1 1
#      value2 2
#      value3 3

func()                               # Calling it without arguments
# No Out put

my_dict = {'foo': 1, 'bar': 2}
func(**my_dict)                      # Calling it with a dictionary
# Out: foo 1
#      bar 2

Vous ne pouvez pas les fournir sans noms, par exemple func(1, 2, 3) va générer une TypeError .

kwargs est un dictionnaire python natif. Par exemple, args['value1'] donnera la valeur de l'argument value1 . Assurez-vous de vérifier au préalable qu'il existe un tel argument ou qu'une KeyError sera KeyError .

Attention

Vous pouvez les mélanger avec d'autres arguments facultatifs et obligatoires, mais l'ordre dans la définition est important.

Les arguments position / mot-clé viennent en premier. (Arguments requis).
Puis viennent les arguments arbitraires *arg . (Optionnel).
Ensuite, les arguments contenant uniquement des mots clés viennent ensuite. (Champs obligatoires).
Enfin, le mot-clé arbitraire **kwargs vient. (Optionnel).

#       |-positional-|-optional-|---keyword-only--|-optional-|
def func(arg1, arg2=10 , *args, kwarg1, kwarg2=2, **kwargs):
     pass
  • arg1 doit être donné, sinon une TypeError est TypeError . Il peut être donné comme positionnel ( func(10) ) ou mot-clé argument ( func(arg1=10) ).
  • kwarg1 doit également être donné, mais il ne peut être fourni qu'en tant que mot-clé: func(kwarg1=10) .
  • arg2 et kwarg2 sont optionnels. Si la valeur doit être modifiée, les mêmes règles que pour arg1 (positionnelle ou mot clé) et kwarg1 (uniquement mot clé) s'appliquent.
  • *args intercepte des paramètres de position supplémentaires. Mais notez que arg1 et arg2 doivent être fournis comme arguments positionnels pour passer des arguments à *args : func(1, 1, 1, 1) .
  • **kwargs attrape tous les paramètres de mots-clés supplémentaires. Dans ce cas, tout paramètre qui n’est pas arg1 , arg2 , kwarg1 ou kwarg2 . Par exemple: func(kwarg3=10) .
  • Dans Python 3, vous pouvez utiliser * seul pour indiquer que tous les arguments suivants doivent être spécifiés en tant que mots-clés. Par exemple, la fonction math.isclose dans Python 3.5 et math.isclose ultérieures est définie à l'aide de def math.isclose (a, b, *, rel_tol=1e-09, abs_tol=0.0) , ce qui signifie que les deux premiers arguments peuvent être fournis Les troisième et quatrième paramètres ne peuvent être fournis que sous forme d'arguments par mots clés.

Python 2.x ne prend pas en charge les paramètres par mot clé uniquement. Ce comportement peut être émulé avec kwargs :

def func(arg1, arg2=10, **kwargs):
    try:
        kwarg1 = kwargs.pop("kwarg1")
    except KeyError:
        raise TypeError("missing required keyword-only argument: 'kwarg1'")

    kwarg2 = kwargs.pop("kwarg2", 2)
    # function body ...

Remarque sur le nommage

La convention de nommage en option des arguments de position args et arguments optionnels mot - clé kwargs est juste une convention que vous pouvez utiliser tous les noms que vous voulez , mais il est utile de suivre la convention pour que les autres savent ce que vous faites, ou vous - même si s'il vous plaît faites plus tard.

Note sur l'unicité

Toute fonction peut être définie avec aucun ou un *args et aucun ou un **kwargs mais pas avec plus d'un de chacun. De plus, *args doit être le dernier argument positionnel et **kwargs doit être le dernier paramètre. Toute tentative d'utiliser plus d'un ou l' autre se traduira par une exception d'erreur de syntaxe.

Remarque sur les fonctions d'imbrication avec des arguments facultatifs

Il est possible d'imbriquer ces fonctions et la convention habituelle consiste à supprimer les éléments que le code a déjà traités, mais si vous transmettez les paramètres, vous devez passer des arguments positionnels optionnels avec un préfixe * et des mots-clés facultatifs args avec un préfixe ** , sinon args with soit passé comme une liste ou tuple et kwargs comme un seul dictionnaire. par exemple:

def fn(**kwargs):
    print(kwargs)
    f1(**kwargs)

def f1(**kwargs):
    print(len(kwargs))

fn(a=1, b=2)
# Out:
# {'a': 1, 'b': 2}
# 2

Définition d'une fonction avec des arguments facultatifs mutables

Il y a un problème lors de l'utilisation d' arguments facultatifs avec un type par défaut mutable (décrit dans Définition d'une fonction avec des arguments facultatifs ), ce qui peut potentiellement conduire à un comportement inattendu.

Explication

Ce problème se pose car les arguments par défaut d’une fonction sont initialisés une fois , au moment où la fonction est définie , et non (comme beaucoup d'autres langages) lorsque la fonction est appelée . Les valeurs par défaut sont stockées dans la variable membre __defaults__ l'objet fonction.

def f(a, b=42, c=[]):
    pass

print(f.__defaults__)
# Out: (42, [])

Pour les types immuables (voir Passage d'argument et mutabilité ), ce n'est pas un problème car il n'y a aucun moyen de modifier la variable. il ne peut jamais être réaffecté, laissant la valeur d'origine inchangée. Par conséquent, les valeurs suivantes sont garanties pour avoir la même valeur par défaut. Cependant, pour un type mutable , la valeur d'origine peut muter, en faisant des appels à ses différentes fonctions membres. Par conséquent, les appels successifs à la fonction ne sont pas garantis pour avoir la valeur par défaut initiale.

def append(elem, to=[]):
    to.append(elem)      # This call to append() mutates the default variable "to"
    return to

append(1)
# Out: [1]

append(2)  # Appends it to the internally stored list
# Out: [1, 2]

append(3, [])  # Using a new created list gives the expected result
# Out: [3]

# Calling it again without argument will append to the internally stored list again
append(4)   
# Out: [1, 2, 4]

Remarque: certains IDE comme PyCharm émettent un avertissement lorsqu'un type mutable est spécifié comme attribut par défaut.

Solution

Si vous voulez vous assurer que l'argument par défaut est toujours celui que vous spécifiez dans la définition de la fonction, la solution consiste à toujours utiliser un type immuable comme argument par défaut.

Un idiome commun pour atteindre cet objectif lorsqu'un type mutable est requis par défaut est d'utiliser None (immuable) comme argument par défaut, puis d'affecter la valeur par défaut réelle à la variable d'argument si elle est égale à None .

def append(elem, to=None):
    if to is None:
        to = []

    to.append(elem)
    return to

Fonctions Lambda (Inline / Anonymous)

Le mot clé lambda crée une fonction en ligne contenant une seule expression. La valeur de cette expression correspond à ce que la fonction renvoie lorsqu'elle est appelée.

Considérez la fonction:

def greeting():
    return "Hello"

qui, lorsqu'il est appelé comme:

print(greeting())

estampes:

Hello

Cela peut être écrit comme une fonction lambda comme suit:

greet_me = lambda: "Hello"

Voir la note au bas de cette section concernant l’affectation des lambdas aux variables. Généralement, ne le faites pas.

Cela crée une fonction en ligne avec le nom greet_me qui renvoie Hello . Notez que vous n'écrivez pas de return lors de la création d'une fonction avec lambda. La valeur après : est automatiquement renvoyée.

Une fois assigné à une variable, il peut être utilisé comme une fonction normale:

print(greet_me())

estampes:

Hello

lambda s peut aussi prendre des arguments:

strip_and_upper_case = lambda s: s.strip().upper()

strip_and_upper_case("  Hello   ")

renvoie la chaîne:

HELLO

Ils peuvent aussi prendre un nombre arbitraire d'arguments / arguments, comme les fonctions normales.

greeting = lambda x, *args, **kwargs: print(x, args, kwargs)
greeting('hello', 'world', world='world')

estampes:

hello ('world',) {'world': 'world'}

lambda s sont couramment utilisés pour les fonctions courtes qui sont pratiques à définir au point où elles sont appelées (généralement avec sorted , filter et map ).

Par exemple, cette ligne trie une liste de chaînes en ignorant leur cas et en ignorant les espaces au début et à la fin:

sorted( [" foo ", "    bAR", "BaZ    "], key=lambda s: s.strip().upper())
# Out:
# ['    bAR', 'BaZ    ', ' foo ']

Liste de tri en ignorant les espaces blancs:

sorted( [" foo ", "    bAR", "BaZ    "], key=lambda s: s.strip())
# Out:
# ['BaZ    ', '    bAR', ' foo ']

Exemples avec map :

sorted( map( lambda s: s.strip().upper(), [" foo ", "    bAR", "BaZ    "]))
# Out:
# ['BAR', 'BAZ', 'FOO']

sorted( map( lambda s: s.strip(), [" foo ", "    bAR", "BaZ    "]))
# Out:
# ['BaZ', 'bAR', 'foo']

Exemples avec des listes numériques:

my_list = [3, -4, -2, 5, 1, 7]
sorted( my_list, key=lambda x: abs(x))
# Out:
# [1, -2, 3, -4, 5, 7]

list( filter( lambda x: x>0, my_list))
# Out:
# [3, 5, 1, 7]

list( map( lambda x: abs(x), my_list))
# Out:
[3, 4, 2, 5, 1, 7]

On peut appeler d'autres fonctions (avec / sans arguments) depuis une fonction lambda.

def foo(msg):
    print(msg)

greet = lambda x = "hello world": foo(x)
greet()

estampes:

hello world

Ceci est utile car lambda peut contenir une seule expression et en utilisant une fonction subsidiaire, on peut exécuter plusieurs instructions.


REMARQUE

Gardez à l'esprit que PEP-8 (le guide de style officiel Python) ne recommande pas d'attribuer les lambdas aux variables (comme nous l'avons fait dans les deux premiers exemples):

Utilisez toujours une instruction def au lieu d'une instruction d'affectation qui lie directement une expression lambda à un identificateur.

Oui:

def f(x): return 2*x

Non:

f = lambda x: 2*x

La première forme signifie que le nom de l’objet fonction résultant est spécifiquement f au lieu du nom générique <lambda> . Ceci est plus utile pour les traces et les représentations de chaînes en général. L'utilisation de l'instruction d'affectation élimine le seul avantage qu'une expression lambda peut offrir sur une instruction def explicite (c'est-à-dire qu'elle peut être incorporée dans une expression plus grande).

Argument passant et mutabilité

D'abord, une terminologie:

  • argument (paramètre actuel ): la variable réelle transmise à une fonction;
  • paramètre (paramètre formel ): la variable de réception utilisée dans une fonction.

En Python, les arguments sont passés par affectation (contrairement aux autres langages, où les arguments peuvent être passés par valeur / référence / pointeur).

  • La mutation d'un paramètre mutera l'argument (si le type de l'argument est modifiable).

    def foo(x):        # here x is the parameter
        x[0] = 9       # This mutates the list labelled by both x and y
        print(x)
    
    y = [4, 5, 6]
    foo(y)             # call foo with y as argument
    # Out: [9, 5, 6]   # list labelled by x has been mutated
    print(y)           
    # Out: [9, 5, 6]   # list labelled by y has been mutated too
    
  • Réaffecter le paramètre ne réassigne pas l'argument.

    def foo(x):        # here x is the parameter, when we call foo(y) we assign y to x
        x[0] = 9       # This mutates the list labelled by both x and y
        x = [1, 2, 3]  # x is now labeling a different list (y is unaffected)
        x[2] = 8       # This mutates x's list, not y's list
      
    y = [4, 5, 6]      # y is the argument, x is the parameter
    foo(y)             # Pretend that we wrote "x = y", then go to line 1
    y
    # Out: [9, 5, 6]
    

En Python, nous n'attribuons pas vraiment de valeurs aux variables, mais nous lions (c'est-à-dire affectons, attachons) des variables (considérées comme des noms ) à des objets.

  • Immuable: nombres entiers, chaînes, tuples, etc. Toutes les opérations font des copies.
  • Mutable: listes, dictionnaires, ensembles, etc. Les opérations peuvent ou non muter.
x = [3, 1, 9]
y = x
x.append(5)    # Mutates the list labelled by x and y, both x and y are bound to [3, 1, 9]
x.sort()       # Mutates the list labelled by x and y (in-place sorting)
x = x + [4]    # Does not mutate the list (makes a copy for x only, not y)
z = x          # z is x ([1, 3, 9, 4])
x += [6]       # Mutates the list labelled by both x and z (uses the extend function).
x = sorted(x)  # Does not mutate the list (makes a copy for x only).
x
# Out: [1, 3, 4, 5, 6, 9]
y
# Out: [1, 3, 5, 9]
z
# Out: [1, 3, 5, 9, 4, 6]

Fermeture

Les fermetures en Python sont créées par des appels de fonction. Ici, l'appel à makeInc crée une liaison pour x référencée à l'intérieur de la fonction inc . Chaque appel à makeInc crée une nouvelle instance de cette fonction, mais chaque instance a un lien vers une liaison différente de x .

def makeInc(x):
  def inc(y):
     # x is "attached" in the definition of inc
     return y + x

  return inc

incOne = makeInc(1)
incFive = makeInc(5)

incOne(5) # returns 6
incFive(5) # returns 10

Notez que bien que dans une fermeture régulière la fonction incluse hérite complètement de toutes les variables de son environnement englobant, dans cette construction, la fonction jointe n'a qu'un accès en lecture aux variables héritées mais ne peut pas leur attribuer

def makeInc(x):
  def inc(y):
     # incrementing x is not allowed
     x += y  
     return x

  return inc

incOne = makeInc(1)
incOne(5) # UnboundLocalError: local variable 'x' referenced before assignment

Python 3 offre l'instruction nonlocal ( variables nonlocal ) pour réaliser une fermeture complète avec des fonctions imbriquées.

Python 3.x 3.0
def makeInc(x):
  def inc(y):
     nonlocal x
     # now assigning a value to x is allowed
     x += y  
     return x

  return inc

incOne = makeInc(1)
incOne(5) # returns 6

Fonctions récursives

Une fonction récursive est une fonction qui s'appelle elle-même dans sa définition. Par exemple, la fonction mathématique, factorielle, définie par factorial(n) = n*(n-1)*(n-2)*...*3*2*1 . peut être programmé comme

def factorial(n):
    #n here should be an integer
    if n == 0:
        return 1
    else:
        return n*factorial(n-1)

les sorties sont les suivantes:

factorial(0)
#out 1
factorial(1)
#out 1
factorial(2)
#out 2
factorial(3)
#out 6

comme prévu. Notez que cette fonction est récursive car le second return factorial(n-1) , où la fonction s'appelle elle-même dans sa définition.

Certaines fonctions récursives peuvent être implémentées en utilisant lambda , la fonction factorielle utilisant lambda serait quelque chose comme ceci:

factorial = lambda n: 1 if n == 0 else n*factorial(n-1)

La fonction produit le même que ci-dessus.

Limite de récursivité

Il y a une limite à la profondeur de la récursion possible, qui dépend de l'implémentation de Python. Lorsque la limite est atteinte, une exception RuntimeError est déclenchée:

def cursing(depth):
  try:
    cursing(depth + 1) # actually, re-cursing
  except RuntimeError as RE:
    print('I recursed {} times!'.format(depth))

cursing(0)
# Out: I recursed 1083 times!

Il est possible de modifier la limite de profondeur de la récursivité en utilisant sys.setrecursionlimit(limit) et en vérifiant cette limite avec sys.getrecursionlimit() .

sys.setrecursionlimit(2000)
cursing(0)
# Out: I recursed 1997 times!

À partir de Python 3.5, l'exception est une RecursionError , dérivée de RuntimeError .

Fonctions imbriquées

Les fonctions en python sont des objets de première classe. Ils peuvent être définis dans n'importe quel domaine

def fibonacci(n):
    def step(a,b):
        return b, a+b
    a, b = 0, 1
    for i in range(n):
        a, b = step(a, b)
    return a

Les fonctions qui capturent leur portée peuvent être transmises comme n'importe quel autre objet

def make_adder(n):
    def adder(x):
        return n + x
    return adder
add5 = make_adder(5)
add6 = make_adder(6)
add5(10)
#Out: 15
add6(10)
#Out: 16

def repeatedly_apply(func, n, x):
    for i in range(n):
        x = func(x)
    return x

repeatedly_apply(add5, 5, 1)
#Out: 26

Débarbouillable et dictionnaire

Les fonctions vous permettent de spécifier ces types de paramètres: positionnel, nommé, variable de position, mot-clé args (kwargs). Voici une utilisation claire et concise de chaque type.

def unpacking(a, b, c=45, d=60, *args, **kwargs):
    print(a, b, c, d, args, kwargs)

>>> unpacking(1, 2)
1 2 45 60 () {}
>>> unpacking(1, 2, 3, 4)
1 2 3 4 () {}
>>> unpacking(1, 2, c=3, d=4)
1 2 3 4 () {}
>>> unpacking(1, 2, d=4, c=3)
1 2 3 4 () {}


>>> pair = (3,)
>>> unpacking(1, 2, *pair, d=4)
1 2 3 4 () {}
>>> unpacking(1, 2, d=4, *pair)
1 2 3 4 () {}
>>> unpacking(1, 2, *pair, c=3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'c'
>>> unpacking(1, 2, c=3, *pair)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'c'

>>> args_list = [3]
>>> unpacking(1, 2, *args_list, d=4)
1 2 3 4 () {}
>>> unpacking(1, 2, d=4, *args_list)
1 2 3 4 () {}
>>> unpacking(1, 2, c=3, *args_list)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'c'
>>> unpacking(1, 2, *args_list, c=3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'c'


>>> pair = (3, 4)
>>> unpacking(1, 2, *pair)
1 2 3 4 () {}
>>> unpacking(1, 2, 3, 4, *pair)
1 2 3 4 (3, 4) {}
>>> unpacking(1, 2, d=4, *pair)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'
>>> unpacking(1, 2, *pair, d=4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'



>>> args_list = [3, 4]
>>> unpacking(1, 2, *args_list)
1 2 3 4 () {}
>>> unpacking(1, 2, 3, 4, *args_list)
1 2 3 4 (3, 4) {}
>>> unpacking(1, 2, d=4, *args_list)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'
>>> unpacking(1, 2, *args_list, d=4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'


>>> arg_dict = {'c':3, 'd':4}
>>> unpacking(1, 2, **arg_dict)
1 2 3 4 () {}
>>> arg_dict = {'d':4, 'c':3}
>>> unpacking(1, 2, **arg_dict)
1 2 3 4 () {}
>>> arg_dict = {'c':3, 'd':4, 'not_a_parameter': 75}
>>> unpacking(1, 2, **arg_dict)
1 2 3 4 () {'not_a_parameter': 75}


>>> unpacking(1, 2, *pair, **arg_dict)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'
>>> unpacking(1, 2, 3, 4, **arg_dict)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'

# Positional arguments take priority over any other form of argument passing
>>> unpacking(1, 2, **arg_dict, c=3)
1 2 3 4 () {'not_a_parameter': 75}
>>> unpacking(1, 2, 3, **arg_dict, c=3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'c'

Forcer l'utilisation de paramètres nommés

Tous les paramètres spécifiés après le premier astérisque dans la signature de la fonction sont uniquement des mots clés.

def f(*a, b):
    pass

f(1, 2, 3)
# TypeError: f() missing 1 required keyword-only argument: 'b'

Dans Python 3, il est possible de placer un seul astérisque dans la signature de la fonction pour s'assurer que les arguments restants ne peuvent être transmis qu'avec des arguments de mots clés.

def f(a, b, *, c):
    pass

f(1, 2, 3)
# TypeError: f() takes 2 positional arguments but 3 were given
f(1, 2, c=3)
# No error

Lambda récursif utilisant une variable affectée

Une méthode pour créer des fonctions lambda récursives consiste à affecter la fonction à une variable, puis à référencer cette variable dans la fonction elle-même. Un exemple courant de ceci est le calcul récursif de la factorielle d'un nombre - tel que montré dans le code suivant:

lambda_factorial = lambda i:1 if i==0 else i*lambda_factorial(i-1)
print(lambda_factorial(4)) # 4 * 3 * 2 * 1 = 12 * 2 = 24

Description du code

La fonction lambda, à travers son affectation de variable, reçoit une valeur (4) qu’elle évalue et retourne 1 si elle est 0 sinon elle renvoie la valeur courante ( i ) * un autre calcul par la fonction lambda de la valeur - 1 ( i-1 ). Cela continue jusqu'à ce que la valeur passée soit décrémentée à 0 ( return 1 ). Un processus qui peut être visualisé comme:

recursive_lambda_path



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow