Python Language
functies
Zoeken…
Invoering
Functies in Python bieden georganiseerde, herbruikbare en modulaire code om een reeks specifieke acties uit te voeren. Functies vereenvoudigen het coderingsproces, voorkomen overbodige logica en maken de code gemakkelijker te volgen. Dit onderwerp beschrijft de declaratie en het gebruik van functies in Python.
Python heeft veel ingebouwde functies zoals print()
, input()
, len()
. Naast ingebouwde functies kunt u ook uw eigen functies maken om meer specifieke taken uit te voeren - deze worden door de gebruiker gedefinieerde functies genoemd .
Syntaxis
- def functienaam ( arg1, ... argN, * args, kw1, kw2 = standaard, ..., ** kwargs ): statements
- lambda arg1, ... argN, * args, kw1, kw2 = standaard, ..., ** kwargs : expressie
parameters
Parameter | Details |
---|---|
arg1 , ..., argN | Reguliere argumenten |
* args | Naamloze positionele argumenten |
kw1 , ..., kwN | Alleen-argumentargumenten |
** kwargs | De overige trefwoordargumenten |
Opmerkingen
5 basisdingen die u met functies kunt doen:
Wijs functies toe aan variabelen
def f(): print(20) y = f y() # Output: 20
Definieer functies binnen andere functies ( geneste functies )
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
Functies kunnen andere functies retourneren
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
Functies kunnen als parameters worden doorgegeven aan andere functies
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
Innerlijke functies hebben toegang tot de omhullende scope ( sluiting )
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!
Aanvullende bronnen
- Meer over functies en decorateurs: https://www.thecodeship.com/patterns/guide-to-python-function-decorators/
Eenvoudige functies definiëren en oproepen
Het gebruik van de def
instructie is de meest gebruikelijke manier om een functie in python te definiëren. Deze instructie is een zogenaamde samengestelde instructie met een enkele clausule met de volgende syntaxis:
def function_name(parameters):
statement(s)
function_name
staat bekend als de identifier van de functie. Aangezien een functiedefinitie een uitvoerbare instructie is, bindt de uitvoering de functienaam aan het functieobject dat later kan worden opgeroepen met behulp van de identifier.
parameters
is een optionele lijst met ID's die gebonden worden aan de waarden die worden parameters
als argumenten wanneer de functie wordt aangeroepen. Een functie kan een willekeurig aantal argumenten hebben die worden gescheiden door komma's.
statement(s)
- ook bekend als de functie-body - zijn een niet-lege reeks instructies die worden uitgevoerd telkens wanneer de functie wordt aangeroepen. Dit betekent dat een functielichaam niet leeg kan zijn, net als elk ingesprongen blok .
Hier is een voorbeeld van een eenvoudige functiedefinitie met als doel Hello
af te drukken telkens wanneer deze wordt genoemd:
def greet():
print("Hello")
Laten we nu de gedefinieerde functie greet()
aanroepen:
greet()
# Out: Hello
Dat is een ander voorbeeld van een functiedefinitie die één enkel argument gebruikt en de doorgegeven waarde weergeeft telkens wanneer de functie wordt aangeroepen:
def greet_two(greeting):
print(greeting)
Daarna moet de functie greet_two()
worden aangeroepen met een argument:
greet_two("Howdy")
# Out: Howdy
U kunt ook een standaardwaarde geven aan dat functieargument:
def greet_two(greeting="Howdy"):
print(greeting)
Nu kunt u de functie oproepen zonder een waarde op te geven:
greet_two()
# Out: Howdy
U zult merken dat u in tegenstelling tot veel andere talen niet expliciet een retourtype van de functie hoeft aan te geven. Python-functies kunnen waarden van elk type return
via het trefwoord return
. Eén functie kan een willekeurig aantal verschillende typen retourneren!
def many_types(x):
if x < 0:
return "Hello!"
else:
return 0
print(many_types(1))
print(many_types(-1))
# Output:
0
Hello!
Zolang dit correct door de beller wordt afgehandeld, is dit een volkomen geldige Python-code.
Een functie die het einde van de uitvoering bereikt zonder een retourinstructie, zal altijd None
retourneren:
def do_nothing():
pass
print(do_nothing())
# Out: None
Zoals eerder vermeld, moet een functiedefinitie een functielichaam hebben, een niet-lege reeks uitspraken. Daarom wordt de pass
instructie als functielichaam gebruikt, wat een null-operatie is - als het wordt uitgevoerd, gebeurt er niets. Het doet wat het betekent, het slaat over. Het is handig als tijdelijke aanduiding wanneer een instructie syntactisch vereist is, maar er geen code hoeft te worden uitgevoerd.
Retourneren van waarden uit functies
Functies kunnen een waarde return
die u direct kunt gebruiken:
def give_me_five():
return 5
print(give_me_five()) # Print the returned value
# Out: 5
of bewaar de waarde voor later gebruik:
num = give_me_five()
print(num) # Print the saved returned value
# Out: 5
of gebruik de waarde voor alle bewerkingen:
print(give_me_five() + 10)
# Out: 15
Als in de functie return
wordt aangetroffen, wordt de functie onmiddellijk verlaten en worden daaropvolgende bewerkingen niet geëvalueerd:
def give_me_another_five():
return 5
print('This statement will not be printed. Ever.')
print(give_me_another_five())
# Out: 5
Je kunt ook meerdere waarden return
(in de vorm van een 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
Een functie zonder return
geeft impliciet None
terug. Evenzo een functie met een return
statement, maar geen return waarde of variabele opbrengsten None
.
Een functie definiëren met argumenten
Argumenten worden tussen haakjes achter de functienaam gedefinieerd:
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)
De functienaam en de lijst met argumenten worden de handtekening van de functie genoemd. Elk genoemd argument is in feite een lokale variabele van de functie.
Wanneer u de functie aanroept, geeft u waarden voor de argumenten door ze in volgorde weer te geven
divide(10, 2)
# output: 5
of specificeer ze in willekeurige volgorde met behulp van de namen uit de functiedefinitie:
divide(divisor=2, dividend=10)
# output: 5
Een functie definiëren met optionele argumenten
Optionele argumenten kunnen worden gedefinieerd door een standaardwaarde aan de argumentnaam toe te kennen (met =
):
def make(action='nothing'):
return action
Het aanroepen van deze functie is op 3 verschillende manieren mogelijk:
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
Waarschuwing
Veranderlijke typen (
list
,dict
,set
, etc.) moeten met zorg worden behandeld wanneer ze als standaardkenmerk worden gegeven. Elke mutatie van het standaardargument zal dit permanent wijzigen. Zie Een functie definiëren met optionele wijzigbare argumenten .
Een functie definiëren met meerdere argumenten
Men kan een functie zoveel argumenten geven als men wil, de enige vaste regels zijn dat elke argumentnaam uniek moet zijn en dat optionele argumenten achter de niet-optionele moeten staan:
def func(value1, value2, optionalvalue=10):
return '{0} {1} {2}'.format(value1, value2, optionalvalue1)
Wanneer u de functie aanroept, kunt u elk trefwoord zonder de naam opgeven, maar dan is de volgorde van belang:
print(func(1, 'a', 100))
# Out: 1 a 100
print(func('abc', 14))
# abc 14 10
Of combineer het geven van de argumenten met naam en zonder. Dan moeten degenen met naam degenen volgen zonder, maar de volgorde van degenen met naam doet er niet toe:
print(func('This', optionalvalue='StackOverflow Documentation', value2='is'))
# Out: This is StackOverflow Documentation
Een functie definiëren met een willekeurig aantal argumenten
Willekeurig aantal positionele argumenten:
Het definiëren van een functie die in staat is om een willekeurig aantal argumenten aan te nemen, kan worden gedaan door een van de argumenten te voorafgaan door een *
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
U kunt geen standaard voor args
, bijvoorbeeld func(*args=[1, 2, 3])
zal een syntaxisfout veroorzaken (zal zelfs niet compileren).
U kunt deze niet bij naam TypeError
wanneer u de functie TypeError
, bijvoorbeeld func(*args=[1, 2, 3])
zal een TypeError
.
Maar als u al uw argumenten in een array (of een andere Iterable
) hebt, kunt u uw functie als volgt aanroepen: func(*my_stuff)
.
Deze argumenten ( *args
) zijn toegankelijk via de index, bijvoorbeeld args[0]
retourneert het eerste argument
Willekeurig aantal trefwoordargumenten
U kunt een willekeurig aantal argumenten met een naam nemen door een argument in de definitie te definiëren met twee *
ervoor:
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
U kunt deze niet zonder namen TypeError
, bijvoorbeeld func(1, 2, 3)
zal een TypeError
.
kwargs
is een eenvoudig native python-woordenboek. args['value1']
geeft bijvoorbeeld de waarde voor argument value1
. Zorg ervoor dat u van tevoren controleert of er een dergelijk argument is of dat KeyError
wordt opgeworpen.
Waarschuwing
U kunt deze combineren met andere optionele en vereiste argumenten, maar de volgorde binnen de definitie is belangrijk.
De argumenten positioneel / trefwoord komen eerst. (Vereiste argumenten).
Dan komen de willekeurige *arg
argumenten. (Optioneel).
Daarna komen alleen argumenten voor zoekwoorden . (Verplicht).
Eindelijk komt het willekeurige trefwoord **kwargs
. (Optioneel).
# |-positional-|-optional-|---keyword-only--|-optional-|
def func(arg1, arg2=10 , *args, kwarg1, kwarg2=2, **kwargs):
pass
-
arg1
moet worden gegeven, anders wordt eenTypeError
opgewekt. Het kan worden gegeven als positioneel (func(10)
) of trefwoordargument (func(arg1=10)
). -
kwarg1
moet ook worden gegeven, maar het kan alleen worden gegeven als trefwoord-argument:func(kwarg1=10)
. -
arg2
enkwarg2
zijn optioneel. Als de waarde moet worden gewijzigd, zijn dezelfde regels als voorarg1
(positioneel of trefwoord) enkwarg1
(alleen trefwoord) van toepassing. -
*args
vangt extra positionele parameters. Merk echter op datarg1
enarg2
moeten worden verstrekt als positionele argumenten om argumenten door te geven aan*args
:func(1, 1, 1, 1)
. -
**kwargs
vangt alle aanvullende trefwoordparameters op. In dit geval elke parameter die nietarg1
,arg2
,kwarg1
ofkwarg2
. Bijvoorbeeld:func(kwarg3=10)
. - In Python 3 kunt u
*
alleen gebruiken om aan te geven dat alle volgende argumenten als trefwoorden moeten worden opgegeven. De functiemath.isclose
in Python 3.5 en hoger wordt bijvoorbeeld gedefinieerd metdef math.isclose (a, b, *, rel_tol=1e-09, abs_tol=0.0)
, wat betekent dat de eerste twee argumenten positioneel kunnen worden geleverd, maar de optionele derde en vierde parameters kunnen alleen worden geleverd als trefwoordargumenten.
Python 2.x ondersteunt geen parameters met alleen zoekwoorden. Dit gedrag kan worden geëmuleerd met 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 ...
Opmerking over naamgeving
De conventie voor het benoemen van optionele positionele argumenten args
en optionele trefwoordargumenten kwargs
is gewoon een conventie die u naar eigen kwargs
kunt gebruiken, maar het is handig om de conventie te volgen, zodat anderen weten wat u doet, of zelfs uzelf later dus.
Opmerking over uniekheid
Elke functie kan worden gedefinieerd met geen of één *args
en geen of één **kwargs
maar niet met meer dan één van elk. Ook *args
moet het laatste positionele argument zijn en **kwargs
moet de laatste parameter zijn. Als u probeert meer dan één van beide te gebruiken , resulteert dit in een syntaxisfoutuitzondering.
Opmerking over nestfuncties met optionele argumenten
Het is mogelijk om dergelijke functies te nesten en de gebruikelijke conventie is om de items te verwijderen die de code al heeft verwerkt, maar als u de parameters doorgeeft, moet u optionele positionele args doorgeven met een *
prefix en optionele trefwoord args met een **
prefix , anders worden args doorgegeven als een lijst of tuple en kwargs als een enkel woordenboek. bijvoorbeeld:
def fn(**kwargs):
print(kwargs)
f1(**kwargs)
def f1(**kwargs):
print(len(kwargs))
fn(a=1, b=2)
# Out:
# {'a': 1, 'b': 2}
# 2
Een functie definiëren met optionele veranderlijke argumenten
Er is een probleem bij het gebruik van optionele argumenten met een veranderlijk standaardtype (beschreven in Een functie definiëren met optionele argumenten ), wat mogelijk kan leiden tot onverwacht gedrag.
Uitleg
Dit probleem doet zich voor omdat de standaardargumenten van een functie eenmaal worden geïnitialiseerd, op het moment waarop de functie is gedefinieerd en niet (zoals veel andere talen) wanneer de functie wordt aangeroepen . De standaardwaarden worden opgeslagen in de __defaults__
het __defaults__
.
def f(a, b=42, c=[]):
pass
print(f.__defaults__)
# Out: (42, [])
Voor onveranderlijke typen (zie Doorgeven van argumenten en veranderbaarheid ) is dit geen probleem omdat er geen manier is om de variabele te muteren; het kan alleen ooit opnieuw worden toegewezen, waardoor de oorspronkelijke waarde ongewijzigd blijft. Daarom hebben daaropvolgende gegarandeerd dezelfde standaardwaarde. Voor een mutable type kan de oorspronkelijke waarde echter muteren door de verschillende lidfuncties aan te roepen. Daarom hebben opeenvolgende aanroepen van de functie niet gegarandeerd de initiële standaardwaarde.
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]
Opmerking: sommige IDE's zoals PyCharm geven een waarschuwing wanneer een veranderlijk type is opgegeven als standaardkenmerk.
Oplossing
Als u ervoor wilt zorgen dat het standaardargument altijd het argument is dat u opgeeft in de functiedefinitie, is de oplossing om altijd een onveranderlijk type als uw standaardargument te gebruiken.
Een veelgebruikt idioom om dit te bereiken wanneer een veranderlijk type als standaard nodig is, is het gebruik van None
(onveranderlijk) als het standaardargument en vervolgens de werkelijke standaardwaarde aan de argumentvariabele toewijzen als deze gelijk is aan None
.
def append(elem, to=None):
if to is None:
to = []
to.append(elem)
return to
Lambda (inline / anoniem) functies
Het lambda
trefwoord maakt een inline-functie die een enkele uitdrukking bevat. De waarde van deze uitdrukking is wat de functie retourneert wanneer deze wordt aangeroepen.
Overweeg de functie:
def greeting():
return "Hello"
welke, wanneer genoemd als:
print(greeting())
prints:
Hello
Dit kan als volgt worden geschreven als een lambdafunctie:
greet_me = lambda: "Hello"
Zie de opmerking onderaan deze sectie over de toewijzing van lambdas aan variabelen. Over het algemeen niet doen.
Hiermee maakt u een inline-functie met de naam greet_me
die Hello
retourneert. Merk op dat je geen return
schrijft bij het maken van een functie met lambda. De waarde na :
wordt automatisch geretourneerd.
Eenmaal toegewezen aan een variabele, kan het net als een normale functie worden gebruikt:
print(greet_me())
prints:
Hello
lambda
kan ook argumenten aanvoeren:
strip_and_upper_case = lambda s: s.strip().upper()
strip_and_upper_case(" Hello ")
geeft de string terug:
HELLO
Ze kunnen ook een willekeurig aantal argumenten / trefwoordargumenten aannemen, zoals normale functies.
greeting = lambda x, *args, **kwargs: print(x, args, kwargs)
greeting('hello', 'world', world='world')
prints:
hello ('world',) {'world': 'world'}
lambda
s worden vaak gebruikt voor korte functies die gemakkelijk te definiëren zijn op het punt waar ze worden aangeroepen (meestal met sorted
, filter
en map
).
Deze regel sorteert bijvoorbeeld een lijst met tekenreeksen die hun hoofdletter negeren en witruimte aan het begin en aan het einde negeren:
sorted( [" foo ", " bAR", "BaZ "], key=lambda s: s.strip().upper())
# Out:
# [' bAR', 'BaZ ', ' foo ']
Sorteerlijst waarbij witruimten worden genegeerd:
sorted( [" foo ", " bAR", "BaZ "], key=lambda s: s.strip())
# Out:
# ['BaZ ', ' bAR', ' foo ']
Voorbeelden met 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']
Voorbeelden met numerieke lijsten:
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]
Men kan andere functies (met / zonder argumenten) vanuit een lambda-functie aanroepen.
def foo(msg):
print(msg)
greet = lambda x = "hello world": foo(x)
greet()
prints:
hello world
Dit is handig omdat lambda
slechts één uitdrukking kan bevatten en door een hulpfunctie te gebruiken, meerdere verklaringen kunnen worden uitgevoerd.
NOTITIE
Houd er rekening mee dat PEP-8 (de officiële gids voor de Python-stijl) niet aanbeveelt lambdas toe te wijzen aan variabelen (zoals we deden in de eerste twee voorbeelden):
Gebruik altijd een def-instructie in plaats van een toewijzingsinstructie die een lambda-expressie rechtstreeks aan een identifier bindt.
Ja:
def f(x): return 2*x
Nee:
f = lambda x: 2*x
De eerste vorm betekent dat de naam van het resulterende functieobject specifiek
f
plaats van de generieke<lambda>
. Dit is in het algemeen nuttiger voor tracebacks en stringrepresentaties. Het gebruik van de toewijzingsinstructie elimineert het enige voordeel dat een lambda-expressie kan bieden ten opzichte van een explicietedef
instructie (dat wil zeggen dat deze kan worden ingebed in een grotere expressie).
Argument doorgeven en veranderlijkheid
Eerst wat terminologie:
- argument ( actuele parameter): de actuele variabele die wordt doorgegeven aan een functie;
- parameter ( formele parameter): de ontvangende variabele die in een functie wordt gebruikt.
In Python worden argumenten doorgegeven door middel van toewijzing (in tegenstelling tot andere talen, waar argumenten kunnen worden doorgegeven door waarde / referentie / pointer).
Het muteren van een parameter zal het argument muteren (als het type van het argument mutabel is).
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
Als u de parameter opnieuw toewijst, wordt het argument niet opnieuw toegewezen.
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]
In Python wijzen we niet echt waarden toe aan variabelen, in plaats daarvan binden we variabelen (beschouwd als namen ) aan objecten.
- Onveranderlijk: gehele getallen, tekenreeksen, tupels, enzovoort. Alle bewerkingen maken kopieën.
- Veranderlijk: lijsten, woordenboeken, sets, enzovoort. Bewerkingen kunnen al dan niet muteren.
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]
Sluiting
Sluitingen in Python worden gemaakt door functie-aanroepen. Hier maakt de aanroep van makeInc
een binding voor x
waarnaar wordt verwezen binnen de functie inc
. Elke aanroep van makeInc
maakt een nieuwe instantie van deze functie, maar elke instantie heeft een link naar een andere binding van 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
Merk op dat terwijl in een regelmatige afsluiting de ingesloten functie alle variabelen volledig overneemt van de omringende omgeving, in deze constructie de ingesloten functie alleen leestoegang heeft tot de overgeërfde variabelen, maar er geen toewijzingen aan kan geven
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 biedt de nonlocal
verklaring (niet- lokale variabelen ) voor het realiseren van een volledige afsluiting met geneste functies.
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
Recursieve functies
Een recursieve functie is een functie die zichzelf in de definitie ervan noemt. Bijvoorbeeld de wiskundige functie, faculteit, gedefinieerd door factorial(n) = n*(n-1)*(n-2)*...*3*2*1
. kan worden geprogrammeerd als
def factorial(n):
#n here should be an integer
if n == 0:
return 1
else:
return n*factorial(n-1)
de uitgangen hier zijn:
factorial(0)
#out 1
factorial(1)
#out 1
factorial(2)
#out 2
factorial(3)
#out 6
zoals verwacht. Merk op dat deze functie recursief is omdat de tweede return factorial(n-1)
, waar de functie zichzelf in zijn definitie aanroept.
Sommige recursieve functies kunnen worden geïmplementeerd met behulp van lambda , de facultaire functie met behulp van lambda zou er ongeveer zo uitzien:
factorial = lambda n: 1 if n == 0 else n*factorial(n-1)
De functie voert hetzelfde uit als hierboven.
Recursielimiet
Er is een limiet aan de diepte van mogelijke recursie, die afhangt van de Python-implementatie. Wanneer de limiet is bereikt, wordt een RuntimeError-uitzondering opgeworpen:
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!
Het is mogelijk om de limiet voor de recursiediepte te wijzigen met sys.setrecursionlimit(limit)
en deze limiet te controleren met sys.getrecursionlimit()
.
sys.setrecursionlimit(2000)
cursing(0)
# Out: I recursed 1997 times!
Van Python 3.5 is de uitzondering een RecursionError
, die is afgeleid van RuntimeError
.
Geneste functies
Functies in python zijn eersteklas objecten. Ze kunnen in elk bereik worden gedefinieerd
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
Functies vangen hun omhullende toepassingsgebied kan worden doorgegeven als elk ander soort object
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
Iterable en woordenboek uitpakken
Met functies kunt u dit soort parameters opgeven: positioneel, benoemd, variabel positioneel, trefwoord args (kwargs). Hier is een duidelijk en beknopt gebruik van elk 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'
Het gebruik van benoemde parameters afdwingen
Alle parameters die zijn opgegeven na het eerste sterretje in de functiehandtekening, zijn alleen sleutelwoorden.
def f(*a, b):
pass
f(1, 2, 3)
# TypeError: f() missing 1 required keyword-only argument: 'b'
In Python 3 is het mogelijk om een asterisk in de functiehandtekening te plaatsen om ervoor te zorgen dat de overige argumenten alleen mogen worden doorgegeven met behulp van trefwoordargumenten.
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
Recursieve Lambda met behulp van toegewezen variabele
Een methode voor het maken van recursieve lambda-functies omvat het toewijzen van de functie aan een variabele en het verwijzen naar die variabele binnen de functie zelf. Een veel voorkomend voorbeeld hiervan is de recursieve berekening van de faculteit van een getal - zoals weergegeven in de volgende code:
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
Beschrijving van de code
De lambdafunctie krijgt via zijn variabele toewijzing een waarde (4) die wordt geëvalueerd en retourneert 1 als deze 0 is of anders retourneert hij de huidige waarde ( i
) * een andere berekening door de lambdafunctie van de waarde - 1 ( i-1
). Dit gaat door totdat de doorgegeven waarde wordt verlaagd tot 0 ( return 1
). Een proces dat kan worden gevisualiseerd als: