Ricerca…


introduzione

Le funzioni in Python forniscono codice organizzato, riutilizzabile e modulare per eseguire una serie di azioni specifiche. Le funzioni semplificano il processo di codifica, impediscono la logica ridondante e rendono il codice più facile da seguire. Questo argomento descrive la dichiarazione e l'utilizzo delle funzioni in Python.

Python ha molte funzioni integrate come print() , input() , len() . Oltre ai built-in è possibile anche creare le proprie funzioni per svolgere lavori più specifici, queste sono chiamate funzioni definite dall'utente .

Sintassi

  • def function_name ( arg1, ... argN, * args, kw1, kw2 = default, ..., ** kwargs ): istruzioni
  • lambda arg1, ... argN, * args, kw1, kw2 = default, ..., ** kwargs : espressione

Parametri

Parametro Dettagli
arg1 , ..., argN Argomenti regolari
* args Argomenti posizionali senza nome
kw1 , ..., kwN Argomenti basati su parole chiave
** kwargs Il resto degli argomenti delle parole chiave

Osservazioni

5 cose basilari che puoi fare con le funzioni:

  • Assegna funzioni alle variabili

    def f():
      print(20)
    y = f
    y()
    # Output: 20
    
  • Definire funzioni all'interno di altre funzioni ( funzioni annidate )

    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
    
  • Le funzioni possono restituire altre funzioni

    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
    
  • Le funzioni possono essere passate come parametri ad altre funzioni

    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
    
  • Le funzioni interne hanno accesso all'ambito di chiusura ( chiusura )

    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!
    

Risorse addizionali

Definire e chiamare semplici funzioni

Usare l'istruzione def è il modo più comune per definire una funzione in python. Questa affermazione è una cosiddetta dichiarazione composta con clausola singola con la seguente sintassi:

def function_name(parameters):
    statement(s)

function_name è noto come identificativo della funzione. Poiché una definizione di funzione è un'istruzione eseguibile, la sua esecuzione associa il nome della funzione all'oggetto funzione che può essere chiamato in seguito utilizzando l'identificatore.

parameters è un elenco opzionale di identificatori che vengono associati ai valori forniti come argomenti quando viene chiamata la funzione. Una funzione può avere un numero arbitrario di argomenti separati da virgole.

statement(s) - noto anche come il corpo della funzione - sono una sequenza non vuota di istruzioni eseguite ogni volta che viene chiamata la funzione. Ciò significa che un corpo della funzione non può essere vuoto, proprio come qualsiasi blocco rientrato .

Ecco un esempio di una definizione di una funzione semplice che ha lo scopo di stampare Hello ogni volta che viene chiamato:

def greet():
    print("Hello")

Chiamiamo ora la funzione greet() definita:

greet()
# Out: Hello

Questo è un altro esempio di una definizione di funzione che prende un singolo argomento e visualizza il valore passato ogni volta che viene chiamata la funzione:

def greet_two(greeting):
    print(greeting)

Dopo che la funzione greet_two() deve essere chiamata con un argomento:

greet_two("Howdy")
# Out: Howdy

Inoltre puoi dare un valore predefinito a quell'argomento di funzione:

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

Ora puoi chiamare la funzione senza dare un valore:

greet_two()
# Out: Howdy 

Noterai che a differenza di molti altri linguaggi, non è necessario dichiarare esplicitamente un tipo di ritorno della funzione. Le funzioni Python possono restituire valori di qualsiasi tipo tramite la parola chiave return . Una funzione può restituire qualsiasi numero di tipi diversi!

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

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

# Output:
0
Hello!

Finché questo è gestito correttamente dal chiamante, questo è un codice Python perfettamente valido.

Una funzione che raggiunge la fine dell'esecuzione senza un'istruzione return restituirà sempre None :

def do_nothing():
    pass

print(do_nothing())
# Out: None

Come accennato in precedenza, una definizione di funzione deve avere un corpo di funzione, una sequenza di dichiarazioni non vuote. Pertanto l'istruzione pass è usata come corpo della funzione, che è un'operazione nulla, quando viene eseguita, non accade nulla. Fa quello che significa, salta. È utile come segnaposto quando un'istruzione è richiesta sintatticamente, ma non è necessario eseguire alcun codice.

Valori di ritorno da funzioni

Le funzioni possono return un valore che è possibile utilizzare direttamente:

def give_me_five():
    return 5

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

o salvare il valore per un uso successivo:

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

oppure utilizzare il valore per qualsiasi operazione:

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

Se si verifica un return nella funzione, la funzione verrà immediatamente chiusa e le successive operazioni non saranno valutate:

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

print(give_me_another_five())
# Out: 5

Puoi anche return più valori (sotto forma di tupla):

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

Una funzione senza dichiarazione di return restituisce implicitamente None . Allo stesso modo una funzione con un'istruzione return , ma nessun valore restituito o variabile restituisce None .

Definire una funzione con argomenti

Gli argomenti sono definiti tra parentesi dopo il nome della funzione:

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)

Il nome della funzione e il suo elenco di argomenti sono chiamati la firma della funzione. Ogni argomento con nome è effettivamente una variabile locale della funzione.

Quando si chiama la funzione, fornire i valori per gli argomenti elencandoli nell'ordine

divide(10, 2)
# output: 5

o specificarli in qualsiasi ordine utilizzando i nomi dalla definizione della funzione:

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

Definizione di una funzione con argomenti opzionali

Gli argomenti facoltativi possono essere definiti assegnando (usando = ) un valore predefinito all'argomento-nome:

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

La chiamata a questa funzione è possibile in 3 modi diversi:

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

avvertimento

I tipi mutabili ( list , dict , set , ecc.) Devono essere trattati con attenzione quando vengono forniti come attributo predefinito . Qualsiasi mutazione dell'argomento predefinito lo cambierà in modo permanente. Vedi Definire una funzione con argomenti mutabili opzionali .

Definizione di una funzione con più argomenti

Si può dare una funzione al numero di argomenti che si desidera, le uniche regole fisse sono che ogni nome di argomento deve essere univoco e che gli argomenti facoltativi devono essere successivi a quelli non facoltativi:

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

Quando si chiama la funzione, è possibile assegnare a ciascuna parola chiave senza il nome, ma l'ordine conta:

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

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

O combinare dando gli argomenti con il nome e senza. Quindi quelli con nome devono seguire quelli senza ma l'ordine di quelli con nome non ha importanza:

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

Definire una funzione con un numero arbitrario di argomenti

Numero arbitrario di argomenti posizionali:

La definizione di una funzione in grado di prendere un numero arbitrario di argomenti può essere effettuata con il prefisso di uno degli argomenti con 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 

Non è possibile fornire un valore predefinito per args , ad esempio func(*args=[1, 2, 3]) genererà un errore di sintassi (non verrà nemmeno compilato).

Non è possibile fornire questi per nome quando si chiama la funzione, ad esempio func(*args=[1, 2, 3]) genererà un TypeError .

Ma se hai già i tuoi argomenti in un array (o qualsiasi altro Iterable ), puoi invocare la tua funzione in questo modo: func(*my_stuff) .

Questi argomenti ( *args ) sono accessibili dall'indice, ad esempio args[0] restituirà il primo argomento

Numero arbitrario di argomenti di parole chiave

Puoi prendere un numero arbitrario di argomenti con un nome definendo un argomento nella definizione con due * di fronte ad esso:

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

Non è possibile fornire questi senza nomi, ad esempio func(1, 2, 3) genererà un TypeError .

kwargs è un semplice dizionario Python nativo. Ad esempio, args['value1'] fornirà il valore per argomento value1 . Assicurati di controllare in anticipo che c'è un tale argomento o che verrà sollevato un KeyError .

avvertimento

È possibile combinarli con altri argomenti opzionali e obbligatori ma l'ordine all'interno della definizione è importante.

Gli argomenti posizionale / parola chiave vengono prima. (Argomenti richiesti).
Poi vengono gli argomenti arbitrari *arg . (Opzionale).
Quindi gli argomenti con parole chiave vengono dopo. (Necessario).
Infine viene la parola chiave arbitraria **kwargs . (Opzionale).

#       |-positional-|-optional-|---keyword-only--|-optional-|
def func(arg1, arg2=10 , *args, kwarg1, kwarg2=2, **kwargs):
     pass
  • deve essere fornito arg1 , altrimenti viene sollevato un TypeError . Può essere dato come argomento posizionale ( func(10) ) o parola chiave ( func(arg1=10) ).
  • kwarg1 deve essere fornito, ma può essere fornito solo come argomento-chiave: func(kwarg1=10) .
  • arg2 e kwarg2 sono opzionali. Se il valore deve essere modificato, si applicano le stesse regole di arg1 (posizionale o parola chiave) e kwarg1 (solo parola chiave).
  • *args acquisisce parametri posizionali aggiuntivi. Ma nota, che arg1 e arg2 devono essere forniti come argomenti posizionali per passare argomenti a *args : func(1, 1, 1, 1) .
  • **kwargs tutti i parametri aggiuntivi delle parole chiave. In questo caso qualsiasi parametro che non sia arg1 , arg2 , kwarg1 o kwarg2 . Ad esempio: func(kwarg3=10) .
  • In Python 3, puoi usare * da solo per indicare che tutti gli argomenti successivi devono essere specificati come parole chiave. Ad esempio la funzione math.isclose in Python 3.5 e successive viene definita usando def math.isclose (a, b, *, rel_tol=1e-09, abs_tol=0.0) , il che significa che i primi due argomenti possono essere forniti in modo posizionale ma facoltativo il terzo e il quarto parametro possono essere forniti solo come argomenti di parole chiave.

Python 2.x non supporta i parametri solo per le parole chiave. Questo comportamento può essere emulato con 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 ...

Nota sulla denominazione

La convenzione di denominazione opzionali argomenti posizionali args e opzionali argomenti chiave kwargs è solo una convenzione è possibile utilizzare qualsiasi nome che ti piace, ma è utile per seguire la convenzione in modo che gli altri sanno cosa si sta facendo, o anche te più tardi quindi per favore fate.

Nota sull'unicità

Qualsiasi funzione può essere definita con none o un *args e nessuno o uno **kwargs ma non con più di uno di ciascuno. Anche *args deve essere l'ultimo argomento posizionale e **kwargs deve essere l'ultimo parametro. Il tentativo di utilizzare più di uno dei due genererà un'eccezione di Errore di sintassi.

Nota sulle funzioni di annidamento con argomenti opzionali

È possibile annidare tali funzioni e la consueta convenzione è rimuovere gli elementi che il codice ha già gestito, ma se si stanno passando i parametri è necessario passare arg facoltativi di posizione con un prefisso * e arg parole facoltative con un prefisso ** , altrimenti gli argomenti vengono passati come elenco o tupla e kwargs come un singolo dizionario. per esempio:

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

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

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

Definizione di una funzione con argomenti mutabili opzionali

C'è un problema quando si usano argomenti opzionali con un tipo predefinito mutabile (descritto in Definire una funzione con argomenti facoltativi ), che può potenzialmente portare a comportamenti imprevisti.

Spiegazione

Questo problema si verifica perché gli argomenti predefiniti di una funzione vengono inizializzati una volta , nel momento in cui viene definita la funzione, e non (come molti altri linguaggi) quando viene chiamata la funzione. I valori predefiniti sono memorizzati nella variabile membro __defaults__ dell'oggetto della __defaults__ .

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

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

Per i tipi immutabili (vedere passaggio degli argomenti e mutabilità ) questo non è un problema perché non c'è modo di mutare la variabile; può essere riassegnato solo sempre, lasciando invariato il valore originale. Quindi, successivamente è garantito avere lo stesso valore di default. Tuttavia, per un tipo mutabile , il valore originale può essere mutato, effettuando chiamate alle sue varie funzioni membro. Di conseguenza, non è garantito che le chiamate successive alla funzione abbiano il valore predefinito iniziale.

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]

Nota: alcuni IDE come PyCharm emetteranno un avviso quando un tipo mutabile viene specificato come attributo predefinito.

Soluzione

Se si desidera assicurarsi che l'argomento predefinito sia sempre quello specificato nella definizione della funzione, la soluzione deve sempre utilizzare un tipo immutabile come argomento predefinito.

Un idioma comune per ottenere ciò quando è necessario un tipo mutabile come predefinito è utilizzare None (immutable) come argomento predefinito e quindi assegnare il valore predefinito effettivo alla variabile argomento se è uguale a None .

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

    to.append(elem)
    return to

Funzioni Lambda (Inline / Anonimo)

La parola chiave lambda crea una funzione inline che contiene una singola espressione. Il valore di questa espressione è ciò che la funzione restituisce quando viene richiamata.

Considera la funzione:

def greeting():
    return "Hello"

che, quando chiamato come:

print(greeting())

stampe:

Hello

Questo può essere scritto come una funzione lambda come segue:

greet_me = lambda: "Hello"

Vedere la nota in fondo a questa sezione riguardante l'assegnazione di lambda alle variabili. Generalmente, non farlo.

Questo crea una funzione inline con il nome greet_me che restituisce Hello . Si noti che non si scrive return quando si crea una funzione con lambda. Il valore dopo : viene automaticamente restituito.

Una volta assegnato a una variabile, può essere utilizzato proprio come una funzione regolare:

print(greet_me())

stampe:

Hello

lambda s può prendere argomenti anche:

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

strip_and_upper_case("  Hello   ")

restituisce la stringa:

HELLO

Possono anche prendere un numero arbitrario di argomenti / argomenti di parole chiave, come le normali funzioni.

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

stampe:

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

lambda vengono comunemente utilizzate per le funzioni brevi che sono convenienti da definire nel punto in cui vengono chiamate (in genere con sorted , filter e map ).

Ad esempio, questa riga ordina un elenco di stringhe che ignorano il loro caso e ignorano gli spazi bianchi all'inizio e alla fine:

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

Ordina la lista semplicemente ignorando gli spazi bianchi:

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

Esempi con la 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']

Esempi con liste numeriche:

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]

Si possono chiamare altre funzioni (con / senza argomenti) dall'interno di una funzione lambda.

def foo(msg):
    print(msg)

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

stampe:

hello world

Ciò è utile perché lambda può contenere solo un'espressione e utilizzando una funzione sussidiaria è possibile eseguire più istruzioni.


NOTA

Ricordare che PEP-8 (la guida di stile Python ufficiale) non consiglia l'assegnazione di lambdas alle variabili (come abbiamo fatto nei primi due esempi):

Usa sempre un'istruzione def invece di un'istruzione di assegnazione che associa un'espressione lambda direttamente a un identificatore.

Sì:

def f(x): return 2*x

No:

f = lambda x: 2*x

Il primo modulo indica che il nome dell'oggetto funzionale risultante è specificamente f invece del generico <lambda> . Questo è più utile per traceback e rappresentazioni di stringhe in generale. L'uso della dichiarazione di assegnazione elimina l'unico vantaggio che un'espressione lambda può offrire rispetto a una dichiarazione di def esplicita (ossia che può essere incorporata in un'espressione più grande).

Passaggio di argomenti e mutabilità

Innanzitutto, alcuni termini:

  • argomento (parametro attuale ): la variabile attuale passata a una funzione;
  • parametro (parametro formale ): la variabile ricevente che viene utilizzata in una funzione.

In Python, gli argomenti vengono passati per assegnazione (al contrario di altri linguaggi, dove gli argomenti possono essere passati per valore / riferimento / puntatore).

  • La modifica di un parametro muterà l'argomento (se il tipo dell'argomento è modificabile).

    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
    
  • La riassegnazione del parametro non riassegnerà l'argomento.

    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, non assegniamo realmente valori alle variabili, ma leghiamo (cioè assegniamo, attribuiamo) variabili (considerate come nomi ) agli oggetti.

  • Immutabile: numeri interi, archi, tuple e così via. Tutte le operazioni fanno copie.
  • Mutabile: elenchi, dizionari, set e così via. Le operazioni possono o non possono mutare.
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]

Chiusura

Le chiusure in Python sono create da chiamate di funzione. Qui, la chiamata a makeInc crea un binding per x cui si fa riferimento all'interno della funzione inc . Ogni chiamata a makeInc crea una nuova istanza di questa funzione, ma ogni istanza ha un collegamento a un diverso bind di 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

Si noti che mentre in una chiusura regolare la funzione racchiusa eredita completamente tutte le variabili dal suo ambiente di chiusura, in questo costrutto la funzione chiusa ha solo accesso in lettura alle variabili ereditate ma non può assegnarle

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'istruzione nonlocal ( Variabili nonlocal ) per realizzare una chiusura completa con funzioni annidate.

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

Funzioni ricorsive

Una funzione ricorsiva è una funzione che si chiama nella sua definizione. Ad esempio la funzione matematica, fattoriale, definita da factorial(n) = n*(n-1)*(n-2)*...*3*2*1 . può essere programmato come

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

le uscite qui sono:

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

come previsto. Si noti che questa funzione è ricorsiva perché il secondo return factorial(n-1) , in cui la funzione si chiama nella sua definizione.

Alcune funzioni ricorsive possono essere implementate usando lambda , la funzione fattoriale che usa lambda sarebbe qualcosa del genere:

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

La funzione restituisce lo stesso come sopra.

Limite di ricorsione

C'è un limite alla profondità della possibile ricorsione, che dipende dall'implementazione di Python. Quando viene raggiunto il limite, viene sollevata un'eccezione RuntimeError:

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!

È possibile modificare il limite di profondità della ricorsione utilizzando sys.setrecursionlimit(limit) e controllare questo limite con sys.getrecursionlimit() .

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

Da Python 3.5, l'eccezione è RecursionError , che deriva da RuntimeError .

Funzioni annidate

Le funzioni in python sono oggetti di prima classe. Possono essere definiti in qualsiasi ambito

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

Le funzioni acquisiscono il loro ambito di inclusione possono essere passate come qualsiasi altro tipo di oggetto

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 e dizionario disimballaggio

Le funzioni consentono di specificare questi tipi di parametri: posizionali, denominati, variabili posizionali, argomenti di parole chiave (kwargs). Ecco un uso chiaro e conciso di ogni tipo.

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'

Forzare l'uso dei parametri denominati

Tutti i parametri specificati dopo il primo asterisco nella firma della funzione sono solo parole chiave.

def f(*a, b):
    pass

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

In Python 3 è possibile inserire un singolo asterisco nella firma della funzione per garantire che gli argomenti rimanenti possano essere passati solo utilizzando gli argomenti delle parole chiave.

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 ricorsivo con variabile assegnata

Un metodo per la creazione di funzioni lambda ricorsive implica l'assegnazione della funzione a una variabile e quindi il riferimento a tale variabile all'interno della funzione stessa. Un esempio comune di questo è il calcolo ricorsivo del fattoriale di un numero, come mostrato nel seguente codice:

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

Descrizione del codice

La funzione lambda, tramite la sua assegnazione di variabili, riceve un valore (4) che valuta e restituisce 1 se è 0 oppure restituisce il valore corrente ( i ) * un altro calcolo dalla funzione lambda del valore - 1 ( i-1 ). Questo continua fino a quando il valore passato viene decrementato a 0 ( return 1 ). Un processo che può essere visualizzato come:

recursive_lambda_path



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow