Python Language
Les fonctions
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
- Plus d'informations sur les fonctions et les décorateurs: https://www.thecodeship.com/patterns/guide-to-python-function-decorators/
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 uneTypeError
estTypeError
. 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
etkwarg2
sont optionnels. Si la valeur doit être modifiée, les mêmes règles que pourarg1
(positionnelle ou mot clé) etkwarg1
(uniquement mot clé) s'appliquent. -
*args
intercepte des paramètres de position supplémentaires. Mais notez quearg1
etarg2
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 pasarg1
,arg2
,kwarg1
oukwarg2
. 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 fonctionmath.isclose
dans Python 3.5 etmath.isclose
ultérieures est définie à l'aide dedef 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 instructiondef
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.
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: