Python Language
funzioni
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
- Altro su funzioni e decoratori: https://www.thecodeship.com/patterns/guide-to-python-function-decorators/
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 unTypeError
. 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
ekwarg2
sono opzionali. Se il valore deve essere modificato, si applicano le stesse regole diarg1
(posizionale o parola chiave) ekwarg1
(solo parola chiave). -
*args
acquisisce parametri posizionali aggiuntivi. Ma nota, chearg1
earg2
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 siaarg1
,arg2
,kwarg1
okwarg2
. 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 funzionemath.isclose
in Python 3.5 e successive viene definita usandodef 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 didef
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.
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: