Skip to content

Commit 77c7f67

Browse files
committed
added info on advanced functions
1 parent 2548dad commit 77c7f67

File tree

1 file changed

+86
-14
lines changed

1 file changed

+86
-14
lines changed

11_decorator_closure.ipynb

Lines changed: 86 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,15 @@
2121
"source": [
2222
"## 🧩 Funzioni come oggetti di prima classe\n",
2323
"\n",
24-
"In Python, le funzioni possono essere trattate come **oggetti**, cioè:\n",
25-
"- possono essere passate come argomento,\n",
26-
"- ritornate da altre funzioni,\n",
27-
"- assegnate a variabili."
24+
"In Python, le funzioni sono considerate **oggetti di prima classe**. Questo significa che puoi trattarle esattamente come qualsiasi altra variabile (come un numero o una lista):\n",
25+
"\n",
26+
"1. **Possono essere assegnate a variabili** (diventano un alias).\n",
27+
"2. **Possono essere passate come argomento** ad altre funzioni (*Higher-Order Functions*).\n",
28+
"3. **Possono essere ritornate** da altre funzioni.\n",
29+
"\n",
30+
"Questo modello flessibile è il fondamento dei *decorator* e del *functional programming* in Python.\n",
31+
"\n",
32+
"### Esempio di Assegnazione e Passaggio come Argomento"
2833
]
2934
},
3035
{
@@ -36,19 +41,28 @@
3641
"def greet(name):\n",
3742
" return f\"Hello, {name}!\"\n",
3843
"\n",
39-
"# Assigning the function to a variable\n",
44+
"# 1. Assigning the function to a variable\n",
4045
"say_hello = greet\n",
46+
"print(say_hello(\"Pythonista\"))\n",
47+
"\n",
48+
"def execute_func(func, arg):\n",
49+
" return func(arg)\n",
4150
"\n",
42-
"print(say_hello(\"Pythonista\"))"
51+
"# 2. Passing the function as an argument\n",
52+
"print(execute_func(greet, \"Tester\"))"
4353
]
4454
},
4555
{
4656
"cell_type": "markdown",
4757
"metadata": {},
4858
"source": [
59+
"--- \n",
60+
"\n",
4961
"## 🧱 Funzioni annidate (Nested Functions)\n",
5062
"\n",
51-
"Una funzione può essere **definita all'interno** di un'altra funzione. Questo è utile per incapsulare logica o creare funzioni di supporto locali."
63+
"Una funzione può essere **definita all'interno** di un'altra funzione. Questo è utile per incapsulare logica o creare funzioni di supporto locali, in quanto la funzione interna è visibile **solo** all'interno della funzione esterna.\n",
64+
"\n",
65+
"**Nota Importante (Scope):** La funzione interna ha accesso alle variabili definite nello *scope* della funzione esterna, anche se non le prende come argomenti. Questo meccanismo è il preludio alle *closure*."
5266
]
5367
},
5468
{
@@ -57,23 +71,33 @@
5771
"metadata": {},
5872
"outputs": [],
5973
"source": [
60-
"def outer_function():\n",
61-
" def inner_function():\n",
62-
" print(\"Inner function executed!\")\n",
74+
"def outer_function(message):\n",
75+
" \n",
76+
" def inner_function(): # Nested function\n",
77+
" print(f\"Inner function executed! The message is: {message}\")\n",
6378
" \n",
6479
" print(\"Outer function running...\")\n",
6580
" inner_function()\n",
6681
"\n",
67-
"outer_function()"
82+
"outer_function(\"Test a nested function\")"
6883
]
6984
},
7085
{
7186
"cell_type": "markdown",
7287
"metadata": {},
7388
"source": [
89+
"--- \n",
90+
"\n",
7491
"## 🌀 Closure\n",
7592
"\n",
76-
"Una **closure** è una funzione che ricorda i valori delle variabili dell’ambiente in cui è stata creata, anche dopo che quell’ambiente è stato distrutto."
93+
"Una **closure** è una funzione annidata che **ricorda i valori delle variabili** dell’ambiente (scope) in cui è stata creata, **anche dopo che quell’ambiente (la funzione esterna) è stato distrutto** (ha terminato l'esecuzione).\n",
94+
"\n",
95+
"Le tre condizioni per una closure sono:\n",
96+
"1. C'è una funzione annidata.\n",
97+
"2. La funzione annidata fa riferimento a una variabile dallo scope della funzione esterna.\n",
98+
"3. La funzione esterna ritorna la funzione annidata.\n",
99+
"\n",
100+
"Le closure permettono di creare **generatori di funzioni**, dove la funzione esterna configura un contesto (il valore di `x`) e la funzione interna lo utilizza in seguito."
77101
]
78102
},
79103
{
@@ -84,11 +108,59 @@
84108
"source": [
85109
"def make_multiplier(x):\n",
86110
" def multiplier(y):\n",
87-
" return x * y # remembers the value of x\n",
111+
" return x * y # closure: remember value of 'x'\n",
88112
" return multiplier\n",
89113
"\n",
114+
"# 2 different functions (closure) with different scope for 'x'\n",
90115
"times3 = make_multiplier(3)\n",
91-
"print(times3(5)) # 15"
116+
"times5 = make_multiplier(5)\n",
117+
"\n",
118+
"print(f\"times3(5) = {times3(5)}\") # 15 (x=3)\n",
119+
"print(f\"times5(5) = {times5(5)}\") # 25 (x=5)"
120+
]
121+
},
122+
{
123+
"cell_type": "markdown",
124+
"metadata": {},
125+
"source": [
126+
"--- \n",
127+
"\n",
128+
"## 🎨 Decorator personalizzati\n",
129+
"\n",
130+
"Un **decorator** è una funzione che prende un'altra funzione e ne estende il comportamento **senza modificarne il codice originale**. Sfrutta in maniera intensiva i concetti di *funzioni di prima classe* e *closure*.\n",
131+
"\n",
132+
"Sintassi base:\n",
133+
"```python\n",
134+
"@decorator_name\n",
135+
"def my_function():\n",
136+
" ...\n",
137+
"```\n",
138+
"\n",
139+
"Questa sintassi è solo *syntactic sugar* (zucchero sintattico) per:\n",
140+
"```python\n",
141+
"my_function = decorator_name(my_function)\n",
142+
"```"
143+
]
144+
},
145+
{
146+
"cell_type": "code",
147+
"execution_count": null,
148+
"metadata": {},
149+
"outputs": [],
150+
"source": [
151+
"def log_call(func):\n",
152+
" def wrapper(*args, **kwargs):\n",
153+
" print(f\"Calling {func.__name__}...\")\n",
154+
" result = func(*args, **kwargs)\n",
155+
" print(f\"{func.__name__} finished!\")\n",
156+
" return result\n",
157+
" return wrapper\n",
158+
"\n",
159+
"@log_call\n",
160+
"def say_hi():\n",
161+
" print(\"Hi there!\")\n",
162+
"\n",
163+
"say_hi()"
92164
]
93165
},
94166
{

0 commit comments

Comments
 (0)