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

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 een TypeError 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 en kwarg2 zijn optioneel. Als de waarde moet worden gewijzigd, zijn dezelfde regels als voor arg1 (positioneel of trefwoord) en kwarg1 (alleen trefwoord) van toepassing.
  • *args vangt extra positionele parameters. Merk echter op dat arg1 en arg2 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 niet arg1 , arg2 , kwarg1 of kwarg2 . 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 functie math.isclose in Python 3.5 en hoger wordt bijvoorbeeld gedefinieerd met def 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 expliciete def 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.

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

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:

recursive_lambda_path



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow