-
Notifications
You must be signed in to change notification settings - Fork 0
/
nomi-dei-metodi-speciali.html
846 lines (760 loc) · 54 KB
/
nomi-dei-metodi-speciali.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
<!DOCTYPE html>
<meta charset=utf-8>
<title>Nomi dei metodi speciali - Immersione in Python 3</title>
<!--[if IE]><script src=j/html5.js></script><![endif]-->
<link rel=stylesheet href=dip3.css>
<style>
h1:before{counter-increment:h1;content:'Appendice B. '}
h2:before{counter-increment:h2;content:'B.' counter(h2) '. '}
h3:before{counter-increment:h3;content:'B.' counter(h2) '.' counter(h3) '. '}
</style>
<link rel=stylesheet media='only screen and (max-device-width: 480px)' href=mobile.css>
<link rel=stylesheet media=print href=print.css>
<meta name=viewport content='initial-scale=1.0'>
<form action=http://www.google.com/cse><div><input type=hidden name=cx value=014021643941856155761:l5eihuescdw><input type=hidden name=ie value=UTF-8> <input type=search name=q size=25 placeholder="powered by Google™"> <input type=submit name=sa value=Search></div></form>
<p>Voi siete qui: <a href=index.html>Inizio</a> <span class=u>‣</span> <a href=indice.html#nomi-dei-metodi-speciali>Immersione in Python 3</a> <span class=u>‣</span>
<p id=level>Livello di difficoltà: <span class=u title=professionale>♦♦♦♦♦</span>
<h1>Nomi dei metodi speciali</h1>
<blockquote class=q>
<p><span class=u>❝</span> La mia specialità è avere ragione quando altri hanno torto. <span class=u>❞</span><br>— <a href=http://en.wikiquote.org/wiki/George_Bernard_Shaw>George Bernard Shaw</a>
</blockquote>
<p id=toc>
<h2 id=divingin>Immersione!</h2>
<p class=f>Vi sono già stati presentati, nel corso di questo libro, alcuni metodi speciali — metodi “magici” che Python invoca quando usate una certa sintassi. Sfruttando i metodi speciali, le vostre classi possono assumere il comportamento di insiemi, dizionari, funzioni, iteratori, o addirittura numeri! Questa appendice serve sia come riferimento per i metodi speciali che abbiamo già visto, sia come breve introduzione ad alcuni dei metodi speciali più esoterici.
<h2 id=basics>Le basi</h2>
<p>Se avete letto <a href=iteratori.html#divingin>l’introduzione alle classi</a>, avete già visto il metodo speciale più comune: il metodo <code>__init__()</code>. La maggior parte delle classi che scrivo finiscono per avere bisogno di un qualche tipo di inizializzazione. Ci sono anche alcuni altri metodi speciali di base che si rivelano particolarmente utili quando dovete effettuare il debug delle vostre classi.
<table>
<tr><th>Note
<th>Voi volete…
<th>Quindi scrivete…
<th>E Python invoca…
<tr><th>①
<td>inizializzare un’istanza
<td><code class=pp>x = MyClass()</code>
<td><a href=http://docs.python.org/3.1/reference/datamodel.html#object.__init__><code>x.<dfn>__init__</dfn>()</code></a>
<tr><th>②
<td>la rappresentazione “ufficiale” sotto forma di stringa
<td><code class=pp><dfn>repr</dfn>(x)</code>
<td><a href=http://docs.python.org/3.1/reference/datamodel.html#object.__repr__><code>x.<dfn>__repr__</dfn>()</code></a>
<tr><th>③
<td>la rappresentazione “informale” sotto forma di stringa
<td><code class=pp><dfn>str</dfn>(x)</code>
<td><a href=http://docs.python.org/3.1/reference/datamodel.html#object.__str__><code>x.<dfn>__str__</dfn>()</code></a>
<tr><th>④
<td>la rappresentazione “informale” sotto forma di array di byte
<td><code class=pp><dfn>bytes</dfn>(x)</code>
<td><code class=pp>x.<dfn>__bytes__</dfn>()</code>
<tr><th>⑤
<td>la rappresentazione sotto forma di stringa formattata
<td><code class=pp>format(x, <var>format_spec</var>)</code>
<td><a href=http://docs.python.org/3.1/reference/datamodel.html#object.__format__><code>x.<dfn>__format__</dfn>(<var>format_spec</var>)</code></a>
</table>
<ol>
<li>Il metodo <code>__init__()</code> viene invocato <em>dopo</em> che l’istanza è stata creata. Se volete controllare l’effettivo processo di creazione, usate <a href=#esoterica>il metodo <code>__new__()</code></a>.
<li>Per convenzione, la stringa restituita dal metodo <code>__repr__()</code> dovrebbe essere un’espressione Python valida.
<li>Il metodo <code>__str__()</code> viene invocato anche quando chiamate <code>print(x)</code>.
<li>Il metodo <code>__bytes__()</code> è <em>una novità di Python 3</em>, dato che il tipo <code>bytes</code> è stato introdotto in questa versione del linguaggio.
<li>Per convenzione, <var>format_spec</var> dovrebbe conformarsi al <a href=http://www.python.org/doc/3.1/library/string.html#formatspec>mini-linguaggio per le specifiche di formato</a>. Il modulo <code>decimal</code> nella libreria standard di Python implementa il proprio metodo <code>__format__()</code>.
</ol>
<h2 id=acts-like-iterator>Classi che si comportano come iteratori</h2>
<p>Nel <a href=iteratori.html>capitolo sugli iteratori</a> avete visto come implementare un iteratore da zero utilizzando i metodi <code>__iter__()</code> e <code>__next__()</code>.
<table>
<tr><th>Note
<th>Voi volete…
<th>Quindi scrivete…
<th>E Python invoca…
<tr><th>①
<td>iterare attraverso una sequenza
<td><code class=pp><dfn>iter</dfn>(seq)</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__iter__><code>seq.<dfn>__iter__</dfn>()</code></a>
<tr><th>②
<td>ottenere il valore successivo da un iteratore
<td><code class=pp><dfn>next</dfn>(seq)</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__next__><code>seq.<dfn>__next__</dfn>()</code></a>
<tr><th>③
<td>creare un iteratore in ordine inverso
<td><code class=pp><dfn>reversed</dfn>(seq)</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__reversed__><code>seq.<dfn>__reversed__</dfn>()</code></a>
</table>
<ol>
<li>Il metodo <code>__iter__()</code> viene invocato ogni volta che create un nuovo iteratore. È un buon posto per inizializzare valori che saranno poi necessari durante l’iterazione.
<li>Il metodo <code>__next__()</code> viene invocato ogni volta che recuperate il valore successivo da un iteratore.
<li>Il metodo <code>__reversed__()</code> è poco comune. Prende una sequenza esistente e restituisce un iteratore che produce gli elementi della sequenza in ordine inverso, dall’ultimo al primo.
</ol>
<p>Come avete visto nel <a href=iteratori.html#a-fibonacci-iterator>capitolo sugli iteratori</a>, un ciclo <code>for</code> può agire su un iteratore. In questo ciclo:
<pre class='nd pp'><code>for x in seq:
print(x)</code></pre>
<p>Python 3 invocherà <code>seq.__iter__()</code> per creare un iteratore, poi invocherà il metodo <code>__next__()</code> su quell’iteratore per ottenere ogni singolo valore di <var>x</var>. Quando il metodo <code>__next__()</code> solleva un’eccezione di tipo <code>StopIteration</code>, il ciclo termina normalmente.
<h2 id=computed-attributes>Attributi calcolati</h2>
<table>
<tr><th>Note
<th>Voi volete…
<th>Quindi scrivete…
<th>E Python invoca…
<tr><th>①
<td>ottenere (incondizionatamente) un attributo calcolato
<td><code class=pp>x.my_property</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__getattribute__><code>x.<dfn>__getattribute__</dfn>(<var>'my_property'</var>)</code></a>
<tr><th>②
<td>ottenere (alternativamente) un attributo calcolato
<td><code class=pp>x.my_property</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__getattr__><code>x.<dfn>__getattr__</dfn>(<var>'my_property'</var>)</code></a>
<tr><th>③
<td>impostare il valore di un attributo
<td><code class=pp>x.my_property = value</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__setattr__><code>x.<dfn>__setattr__</dfn>(<var>'my_property'</var>, <var>value</var>)</code></a>
<tr><th>④
<td>eliminare un attributo
<td><code class=pp>del x.my_property</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__delattr__><code>x.<dfn>__delattr__</dfn>(<var>'my_property'</var>)</code></a>
<tr><th>⑤
<td>elencare tutti gli attributi e i metodi
<td><code class=pp>dir(x)</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__dir__><code>x.<dfn>__dir__</dfn>()</code></a>
</table>
<ol>
<li>Se la vostra classe definisce un metodo <code>__getattribute__()</code>, Python lo invocherà <em>ogni volta che fate riferimento al nome di un attributo o di un metodo qualsiasi</em> (a parte i nomi dei metodi speciali, dato che questo causerebbe uno spiacevole ciclo infinito).
<li>Se la vostra classe definisce un metodo <code>__getattr__()</code>, Python lo invocherà solo dopo aver cercato l’attributo in tutti i posti in cui viene cercato normalmente. Se un’istanza <var>x</var> definisce un attributo <var>color</var>, l’accesso a <var>x.color</var> <em>non</em> causerà l’invocazione di <code>x.__getattr__('color')</code> ma restituirà semplicemente il valore di <var>x.color</var> già definito.
<li>Il metodo <code>__setattr__()</code> viene invocato ogni volta che assegnate un valore a un attributo.
<li>Il metodo <code>__delattr__()</code> viene invocato ogni volta che eliminate un attributo.
<li>Il metodo <code>__dir__()</code> è utile se definite un metodo <code>__getattr__()</code> o un metodo <code>__getattribute__()</code>. Generalmente, l’invocazione di <code>dir(x)</code> elenca solo gli attributi e i metodi normali. Se il vostro metodo <code>__getattr__()</code> gestisce dinamicamente un attributo <var>color</var>, <code>dir(x)</code> non mostrerà <var>color</var> come uno degli attributi disponibili. Fornire una vostra implementazione del metodo <code>__dir__()</code> vi permette di mostrare <var>color</var> nell’elenco degli attributi disponibili, venendo in aiuto ad altri programmatori che vorrebbero usare la vostra classe senza doverne esaminare i dettagli interni.
</ol>
<p>La distinzione tra i metodi <code>__getattr__()</code> e <code>__getattribute__()</code> è sottile ma importante. Posso spiegarla con due esempi:
<pre class=screen>
<code>class Dynamo:
def __getattr__(self, key):
<a> if key == 'color': <span class=u>①</span></a>
return 'PapayaWhip'
else:
<a> raise AttributeError <span class=u>②</span></a></code>
<samp class=p>>>> </samp><kbd class=pp>dyn = Dynamo()</kbd>
<a><samp class=p>>>> </samp><kbd class=pp>dyn.color</kbd> <span class=u>③</span></a>
<samp class=pp>'PapayaWhip'</samp>
<samp class=p>>>> </samp><kbd class=pp>dyn.color = 'LemonChiffon'</kbd>
<a><samp class=p>>>> </samp><kbd class=pp>dyn.color</kbd> <span class=u>④</span></a>
<samp class=pp>'LemonChiffon'</samp></pre>
<ol>
<li>Il nome dell’attributo viene passato al metodo <code>__getattr__()</code> sotto forma di stringa. Se il nome è <code>'color'</code>, il metodo restituisce un valore. (In questo caso il valore è solo una stringa costante, ma normalmente effettuereste una qualche sorta di computazione e ne restituireste il risultato.)
<li>Se il nome dell’attributo è sconosciuto, il metodo <code>__getattr__()</code> deve sollevare un’eccezione di tipo <code>AttributeError</code>, altrimenti il vostro codice fallirà silenziosamente quando accedete ad attributi non definiti. (Tecnicamente, se il metodo non solleva un’eccezione o restituisce esplicitamente un valore, allora restituisce <code>None</code>, il valore nullo di Python. In questo caso <em>tutti</em> gli attributi non esplicitamente definiti varrebbero <code>None</code>, che quasi sicuramente non è ciò che volete.)
<li>L’istanza <var>dyn</var> non ha un attributo chiamato <var>color</var>, quindi il metodo <code>__getattr__()</code> viene invocato per fornirne il valore calcolato.
<li>Dopo aver esplicitamente impostato <var>dyn.color</var>, il metodo <code>__getattr__()</code> non viene più invocato per fornire il valore di <var>dyn.color</var> perché <var>dyn.color</var> è già definito in questa istanza.
</ol>
<p>D’altra parte, il metodo <code>__getattribute__()</code> viene invocato in maniera assoluta e incondizionata.
<pre class=screen>
<code>class SuperDynamo:
def __getattribute__(self, key):
if key == 'color':
return 'PapayaWhip'
else:
raise AttributeError</code>
<samp class=p>>>> </samp><kbd class=pp>dyn = SuperDynamo()</kbd>
<a><samp class=p>>>> </samp><kbd class=pp>dyn.color</kbd> <span class=u>①</span></a>
<samp class=pp>'PapayaWhip'</samp>
<samp class=p>>>> </samp><kbd class=pp>dyn.color = 'LemonChiffon'</kbd>
<a><samp class=p>>>> </samp><kbd class=pp>dyn.color</kbd> <span class=u>②</span></a>
<samp class=pp>'PapayaWhip'</samp></pre>
<ol>
<li>Il metodo <code>__getattribute__()</code> viene invocato per fornire il valore di <var>dyn.color</var>.
<li>Anche dopo aver esplicitamente impostato <var>dyn.color</var>, il metodo <code>__getattribute__()</code> <em>viene ancora invocato</em> per fornirne il valore. Se esiste, il metodo <code>__getattribute__()</code> <em>viene invocato incondizionatamente</em> per ogni accesso ad attributi e metodi, anche per attributi che avete esplicitamente impostato dopo la creazione di un’istanza.
</ol>
<blockquote class=note>
<p><span class=u>☞</span>Se la vostra classe definisce un metodo <code>__getattribute__()</code>, vorrete probabilmente definire anche un metodo <code>__setattr__()</code> e coordinare i due per tenere traccia del valore degli attributi. Altrimenti, qualsiasi attributo che impostiate dopo aver creato un’istanza scomparirà in un buco nero.
</blockquote>
<p>Dovete usare il metodo <code>__getattribute__()</code> con particolare attenzione, perché viene invocato anche quando Python cerca il nome di un metodo nella vostra classe.
<pre class=screen>
<code>class Rastan:
def __getattribute__(self, key):
<a> raise AttributeError <span class=u>①</span></a>
def swim(self):
pass</code>
<samp class=p>>>> </samp><kbd class=pp>hero = Rastan()</kbd>
<a><samp class=p>>>> </samp><kbd class=pp>hero.swim()</kbd> <span class=u>②</span></a>
<samp class=traceback>Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __getattribute__
AttributeError</samp></pre>
<ol>
<li>Questa classe definisce un metodo <code>__getattribute__()</code> che solleva sempre un’eccezione di tipo <code>AttributeError</code>. Nessun accesso ad attributi o metodi avrà successo.
<li>Quando invocate <code>hero.swim()</code>, Python cerca un metodo <code>swim()</code> nella classe <code>Rastan</code>. Questa ricerca passa attraverso il metodo <code>__getattribute__()</code>, <em>perché tutti gli accessi ad attributi e metodi passano attraverso il metodo <code>__getattribute__()</code></em>. In questo caso il metodo <code>__getattribute__()</code> solleva un’eccezione di tipo <code>AttributeError</code>, quindi l’accesso al metodo fallisce, quindi la chiamata di metodo fallisce.
</ol>
<h2 id=acts-like-function>Classi che si comportano come funzioni</h2>
<p>Potete rendere invocabile un’istanza di una classe — esattamente come è invocabile una funzione — definendo il metodo <code>__call__()</code>.
<table>
<tr><th>Note
<th>Voi volete…
<th>Quindi scrivete…
<th>E Python invoca…
<tr><th>
<td>“invocare” un’istanza come una funzione
<td><code class=pp>my_instance()</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__call__><code>my_instance.<dfn>__call__</dfn>()</code></a>
</table>
<p>Il <a href=http://docs.python.org/3.1/library/zipfile.html>modulo <code>zipfile</code></a> usa questa tecnica per definire una classe che possa <dfn>decodificare</dfn> un file <dfn>zip</dfn> <dfn>criptato</dfn> con una certa password. L’algoritmo di <dfn>decodifica</dfn> per i file zip richiede di memorizzare uno stato durante l’esecuzione. Definire il decodificatore come una classe vi permette di mantenere questo stato all’interno di una singola istanza di tale classe. Lo stato viene inizializzato nel metodo <code>__init__()</code> e aggiornato man mano che il file viene <dfn>decodificato</dfn>. Ma dato che la classe è anche “invocabile” come una funzione, potete passare l’istanza come primo argomento alla funzione <code>map()</code> in questo modo:
<pre class=pp><code># estratto da zipfile.py
class _ZipDecrypter:
.
.
.
def __init__(self, pwd):
<a> self.key0 = 305419896 <span class=u>①</span></a>
self.key1 = 591751049
self.key2 = 878082192
for p in pwd:
self._UpdateKeys(p)
<a> def __call__(self, c): <span class=u>②</span></a>
assert isinstance(c, int)
k = self.key2 | 2
c = c ^ (((k * (k^1)) >> 8) & 255)
self._UpdateKeys(c)
return c
.
.
.
<a>zd = _ZipDecrypter(pwd) <span class=u>③</span></a>
bytes = zef_file.read(12)
<a>h = list(map(zd, bytes[0:12])) <span class=u>④</span></a></code></pre>
<ol>
<li>La classe <code>_ZipDecrypter</code> mantiene il proprio stato sotto forma di tre chiavi di cifratura, che vengono successivamente aggiornate facendone ruotare i bit nel metodo <code>_UpdateKeys()</code> (che qui non viene mostrato).
<li>La classe definisce un metodo <code>__call__()</code> che rende le istanze di questa classe invocabili come funzioni. In questo caso il metodo <code>__call__()</code> decodifica un singolo byte del file zip, quindi aggiorna le chiavi di cifratura sulla base del byte che è stato decodificato.
<li><var>zd</var> è un’istanza della classe <code>_ZipDecrypter</code>. La variabile <var>pwd</var> viene passata al metodo <code>__init__()</code>, dove viene memorizzata e usata per aggiornare le chiavi di cifratura per la prima volta.
<li>Dati i primi 12 byte di un file zip, li decodificate applicando <var>zd</var> ai byte, in sostanza “invocando” 12 volte <var>zd</var>, quindi invocando 12 volte il metodo <code>__call__()</code>, che per 12 volte aggiorna lo stato interno del decodificatore e restituisce un byte come risultato.
</ol>
<h2 id=acts-like-set>Classi che si comportano come insiemi</h2>
<p>Nel caso la vostra classe agisca come contenitore per un insieme di valori — cioè nel caso abbia senso chiedere se la vostra classe “contiene” un valore — allora dovrebbe probabilmente definire i seguenti metodi speciali che le permettono di assumere il comportamento di un insieme.
<table>
<tr><th>Note
<th>Voi volete…
<th>Quindi scrivete…
<th>E Python invoca…
<tr><th>
<td>il numero di elementi
<td><code class=pp><dfn>len</dfn>(s)</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__len__><code>s.<dfn>__len__</dfn>()</code></a>
<tr><th>
<td>sapere se contiene uno specifico valore
<td><code class=pp>x in s</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__contains__><code>s.<dfn>__contains__</dfn>(<var>x</var>)</code></a>
</table>
<p id=acts-like-set-example>Il <a href=http://docs.python.org/3.1/library/cgi.html>modulo <code>cgi</code></a> sfrutta questi metodi nella sua classe <code>FieldStorage</code>, che rappresenta tutti i campi di una form o i parametri di richiesta inviati a una pagina web dinamica.
<pre class=pp><code># Uno script che risponde a http://example.com/search?q=cgi
import cgi
fs = cgi.FieldStorage()
<a>if 'q' in fs: <span class=u>①</span></a>
do_search()
# Un estratto da cgi.py che spiega come funziona lo script
class FieldStorage:
.
.
.
<a> def __contains__(self, key): <span class=u>②</span></a>
if self.list is None:
raise TypeError('not indexable')
<a> return any(item.name == key for item in self.list) <span class=u>③</span></a>
<a> def __len__(self): <span class=u>④</span></a>
<a> return len(self.keys()) <span class=u>⑤</span></a></code></pre>
<ol>
<li>Una volta creata un’istanza della classe <code>cgi.FieldStorage</code>, potete usare l’operatore “<code>in</code>” per controllare se un particolare parametro è stato incluso nella stringa di richiesta.
<li>Il metodo <code>__contains__()</code> è la magia che fa funzionare quel controllo.
<li>Quando dite <code>if 'q' in fs</code>, Python cerca nell’oggetto <var>fs</var> il metodo <code>__contains__()</code>, che è definito in <code>cgi.py</code>. Il valore <code>'q'</code> è passato al metodo <code>__contains__()</code> come argomento <var>key</var>.
<li>La stessa classe <code>FieldStorage</code> è in grado di restituire il valore della propria lunghezza, quindi <code>len(<var>fs</var>)</code> invocherà il metodo <code>__len__()</code> sull’istanza della classe <code>FieldStorage</code> per restituire il numero di parametri di richiesta che sono stati identificati.
<li>Il metodo <code>self.keys()</code> verifica se <code>self.list is None</code>, quindi il metodo <code>__len__()</code> non ha bisogno di duplicare questo controllo di errore.
</ol>
<h2 id=acts-like-dict>Classi che si comportano come dizionari</h2>
<p>Estendendo un poco la sezione precedente, potete definire classi che non solo rispondono all’operatore “<code>in</code>” e alla funzione <code>len()</code>, ma che si comportano come dizionari veri e propri, restituendo valori sulla base di chiavi.
<table>
<tr><th>Note
<th>Voi volete…
<th>Quindi scrivete…
<th>E Python invoca…
<tr><th>
<td>ottenere un valore tramite la sua chiave
<td><code class=pp>x[key]</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__getitem__><code>x.<dfn>__getitem__</dfn>(<var>key</var>)</code></a>
<tr><th>
<td>impostare un valore tramite la sua chiave
<td><code class=pp>x[key] = value</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__setitem__><code>x.<dfn>__setitem__</dfn>(<var>key</var>, <var>value</var>)</code></a>
<tr><th>
<td>eliminare una coppia chiave-valore
<td><code class=pp>del x[key]</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__delitem__><code>x.<dfn>__delitem__</dfn>(<var>key</var>)</code></a>
<tr><th>
<td>fornire un valore predefinito per chiavi mancanti
<td><code class=pp>x[nonexistent_key]</code>
<td><a href=http://docs.python.org/3.1/library/collections.html#collections.defaultdict.__missing__><code>x.<dfn>__missing__</dfn>(<var>nonexistent_key</var>)</code></a>
</table>
<p>La <a href=#acts-like-set-example>classe <code>FieldStorage</code></a> del <a href=http://docs.python.org/3.1/library/cgi.html>modulo <code>cgi</code></a> definisce anche questi metodi speciali in modo che possiate fare cose come queste:
<pre class=pp><code># Uno script che risponde a http://example.com/search?q=cgi
import cgi
fs = cgi.FieldStorage()
if 'q' in fs:
<a> do_search(fs['q']) <span class=u>①</span></a>
# Un estratto da cgi.py che spiega come funziona lo script
class FieldStorage:
.
.
.
<a> def __getitem__(self, key): <span class=u>②</span></a>
if self.list is None:
raise TypeError('not indexable')
found = []
for item in self.list:
if item.name == key: found.append(item)
if not found:
raise KeyError(key)
if len(found) == 1:
return found[0]
else:
return found</code></pre>
<ol>
<li>L’oggetto <var>fs</var> è un’istanza di <code>cgi.FieldStorage</code>, tuttavia potete valutare espressioni come <code>fs['q']</code>.
<li><code>fs['q']</code> invoca il metodo <code>__getitem__()</code> con il parametro <var>key</var> impostato a <code>'q'</code>. Quindi controlla se la lista di parametri di richiesta che mantiene internamente (<var>self.list</var>) contiene un elemento il cui attributo <code>name</code> corrisponde alla chiave data.
</ol>
<h2 id=acts-like-number>Classi che si comportano come numeri</h2>
<p>Usando i metodi speciali appropriati, potete definire classi che si comportano come numeri. Questo significa che potete sommarle, sottrarle ed eseguire su di esse altre operazioni matematiche. Questo è il modo in cui sono realizzate le <dfn>frazioni</dfn> — la classe <code><dfn>Fraction</dfn></code> implementa questi metodi speciali in modo che possiate fare cose come questa:
<pre class=screen>
<samp class=p>>>> </samp><kbd class=pp>from fractions import Fraction</kbd>
<samp class=p>>>> </samp><kbd class=pp>x = Fraction(1, 3)</kbd>
<samp class=p>>>> </samp><kbd class=pp>x / 3</kbd>
<samp class=pp>Fraction(1, 9)</samp></pre>
<p>Ecco la lista completa dei metodi speciali che dovete implementare per avere una classe simile ai numeri.
<table>
<tr><th>Note
<th>Voi volete…
<th>Quindi scrivete…
<th>E Python invoca…
<tr><th>
<td>addizione
<td><code class=pp>x + y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__add__><code>x.<dfn>__add__</dfn>(<var>y</var>)</code></a>
<tr><th>
<td>sottrazione
<td><code class=pp>x - y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__sub__><code>x.<dfn>__sub__</dfn>(<var>y</var>)</code></a>
<tr><th>
<td>moltiplicazione
<td><code class=pp>x * y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__mul__><code>x.<dfn>__mul__</dfn>(<var>y</var>)</code></a>
<tr><th>
<td>divisione
<td><code class=pp>x / y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__truediv__><code>x.<dfn>__truediv__</dfn>(<var>y</var>)</code></a>
<tr><th>
<td>divisione intera
<td><code>x // y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__floordiv__><code>x.<dfn>__floordiv__</dfn>(<var>y</var>)</code></a>
<tr><th>
<td>modulo (resto)
<td><code class=pp>x % y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__mod__><code>x.<dfn>__mod__</dfn>(<var>y</var>)</code></a>
<tr><th>
<td>divisione intera <i class=baa>&</i> modulo
<td><code class=pp>divmod(x, y)</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__divmod__><code>x.<dfn>__divmod__</dfn>(<var>y</var>)</code></a>
<tr><th>
<td>elevamento a potenza
<td><code class=pp>x ** y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__pow__><code>x.<dfn>__pow__</dfn>(<var>y</var>)</code></a>
<tr><th>
<td>scorrimento a sinistra
<td><code class=pp>x << y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__lshift__><code>x.<dfn>__lshift__</dfn>(<var>y</var>)</code></a>
<tr><th>
<td>scorrimento a destra
<td><code class=pp>x >> y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__rshift__><code>x.<dfn>__rshift__</dfn>(<var>y</var>)</code></a>
<tr><th>
<td><code class=pp>and</code> bit per bit
<td><code class=pp>x & y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__and__><code>x.<dfn>__and__</dfn>(<var>y</var>)</code></a>
<tr><th>
<td><code class=pp>xor</code> bit per bit
<td><code class=pp>x ^ y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__xor__><code>x.<dfn>__xor__</dfn>(<var>y</var>)</code></a>
<tr><th>
<td><code class=pp>or</code> bit per bit
<td><code class=pp>x | y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__or__><code>x.<dfn>__or__</dfn>(<var>y</var>)</code></a>
</table>
<p>Tutto questo va bene se <var>x</var> è un’istanza di una classe che implementa questi metodi. Ma cosa succede se non ne implementa uno? O peggio, cosa succede se lo implementa, ma non può gestire certi tipi di argomenti? Per esempio:
<pre class=screen>
<samp class=p>>>> </samp><kbd class=pp>from fractions import Fraction</kbd>
<samp class=p>>>> </samp><kbd class=pp>x = Fraction(1, 3)</kbd>
<samp class=p>>>> </samp><kbd class=pp>1 / x</kbd>
<samp class=pp>Fraction(3, 1)</samp></pre>
<p>Questo <em>non</em> è il caso in cui un oggetto <code>Fraction</code> viene diviso per un intero (come nell’esempio precedente). Quel caso era semplice: <code>x / 3</code> invoca <code>x.__truediv__(3)</code> e il metodo <code>__truediv__()</code> della classe <code>Fraction</code> gestisce tutta la matematica coinvolta. Ma gli interi non “sanno” come fare operazioni aritmetiche con le frazioni. Quindi come mai questo esempio funziona?
<p>Esiste un secondo insieme di metodi speciali per l’aritmetica con <i>operandi rovesciati</i>. Data un’operazione aritmetica con due operandi (<i>e.g.</i> <code>x / y</code>), ci sono due modi di eseguirla:
<ol>
<li>dire a <var>x</var> di dividersi per <var>y</var>, oppure
<li>dire a <var>y</var> di dividere <var>x</var> per lei stessa.
</ol>
<p>L’insieme di metodi speciali appena visto adotta il primo approccio: dato <code>x / y</code>, fornisce a <var>x</var> un modo per dire: “So come dividermi per <var>y</var>.” L’insieme di metodi speciali che segue adotta il secondo approccio, fornendo a <var>y</var> un modo per dire: “So come fare il denominatore e dividere <var>x</var> per me stessa.”
<table>
<tr><th>Note
<th>Voi volete…
<th>Quindi scrivete…
<th>E Python invoca…
<tr><th>
<td>addizione
<td><code class=pp>x + y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__radd__><code>y.<dfn>__radd__</dfn>(<var>x</var>)</code></a>
<tr><th>
<td>sottrazione
<td><code class=pp>x - y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__rsub__><code>y.<dfn>__rsub__</dfn>(<var>x</var>)</code></a>
<tr><th>
<td>moltiplicazione
<td><code class=pp>x * y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__rmul__><code>y.<dfn>__rmul__</dfn>(<var>x</var>)</code></a>
<tr><th>
<td>divisione
<td><code class=pp>x / y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__rtruediv__><code>y.<dfn>__rtruediv__</dfn>(<var>x</var>)</code></a>
<tr><th>
<td>divisione intera
<td><code>x // y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__rfloordiv__><code>y.<dfn>__rfloordiv__</dfn>(<var>x</var>)</code></a>
<tr><th>
<td>modulo (resto)
<td><code class=pp>x % y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__rmod__><code>y.<dfn>__rmod__</dfn>(<var>x</var>)</code></a>
<tr><th>
<td>divisione intera <i class=baa>&</i> modulo
<td><code class=pp>divmod(x, y)</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__rdivmod__><code>y.<dfn>__rdivmod__</dfn>(<var>x</var>)</code></a>
<tr><th>
<td>elevamento a potenza
<td><code class=pp>x ** y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__rpow__><code>y.<dfn>__rpow__</dfn>(<var>x</var>)</code></a>
<tr><th>
<td>scorrimento a sinistra
<td><code class=pp>x << y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__rlshift__><code>y.<dfn>__rlshift__</dfn>(<var>x</var>)</code></a>
<tr><th>
<td>scorrimento a destra
<td><code class=pp>x >> y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__rrshift__><code>y.<dfn>__rrshift__</dfn>(<var>x</var>)</code></a>
<tr><th>
<td><code class=pp>and</code> bit per bit
<td><code class=pp>x & y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__rand__><code>y.<dfn>__rand__</dfn>(<var>x</var>)</code></a>
<tr><th>
<td><code class=pp>xor</code> bit per bit
<td><code class=pp>x ^ y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__rxor__><code>y.<dfn>__rxor__</dfn>(<var>x</var>)</code></a>
<tr><th>
<td><code class=pp>or</code> bit per bit
<td><code class=pp>x | y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__ror__><code>y.<dfn>__ror__</dfn>(<var>x</var>)</code></a>
</table>
<p>Ma aspettate! C’è di più! Se state eseguendo operazioni “in loco”, come <code>x /= 3</code>, ci sono ancora altri metodi speciali aggiuntivi che potete definire.
<table>
<tr><th>Note
<th>Voi volete…
<th>Quindi scrivete…
<th>E Python invoca…
<tr><th>
<td>addizione in loco
<td><code class=pp>x += y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__iadd__><code>x.<dfn>__iadd__</dfn>(<var>y</var>)</code></a>
<tr><th>
<td>sottrazione in loco
<td><code class=pp>x -= y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__isub__><code>x.<dfn>__isub__</dfn>(<var>y</var>)</code></a>
<tr><th>
<td>moltiplicazione in loco
<td><code class=pp>x *= y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__imul__><code>x.<dfn>__imul__</dfn>(<var>y</var>)</code></a>
<tr><th>
<td>divisione in loco
<td><code class=pp>x /= y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__itruediv__><code>x.<dfn>__itruediv__</dfn>(<var>y</var>)</code></a>
<tr><th>
<td>divisione intera in loco
<td><code>x //= y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__ifloordiv__><code>x.<dfn>__ifloordiv__</dfn>(<var>y</var>)</code></a>
<tr><th>
<td>modulo in loco
<td><code class=pp>x %= y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__imod__><code>x.<dfn>__imod__</dfn>(<var>y</var>)</code></a>
<tr><th>
<td>elevamento a potenza in loco
<td><code class=pp>x **= y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__ipow__><code>x.<dfn>__ipow__</dfn>(<var>y</var>)</code></a>
<tr><th>
<td>scorrimento a sinistra in loco
<td><code class=pp>x <<= y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__ilshift__><code>x.<dfn>__ilshift__</dfn>(<var>y</var>)</code></a>
<tr><th>
<td>scorrimento a destra in loco
<td><code class=pp>x >>= y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__irshift__><code>x.<dfn>__irshift__</dfn>(<var>y</var>)</code></a>
<tr><th>
<td><code class=pp>and</code> bit per bit in loco
<td><code class=pp>x &= y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__iand__><code>x.<dfn>__iand__</dfn>(<var>y</var>)</code></a>
<tr><th>
<td><code class=pp>xor</code> bit per bit in loco
<td><code class=pp>x ^= y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__ixor__><code>x.<dfn>__ixor__</dfn>(<var>y</var>)</code></a>
<tr><th>
<td><code class=pp>or</code> bit per bit in loco
<td><code class=pp>x |= y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__ior__><code>x.<dfn>__ior__</dfn>(<var>y</var>)</code></a>
</table>
<p>Notate che la maggior parte dei metodi per le operazioni in loco non è richiesta. Se non definite il metodo per una particolare operazione in loco, Python proverà a utilizzare gli altri metodi. Per esempio, cercando di eseguire l’espressione <code>x /= y</code>, Python proverà a…
<ol>
<li>Invocare <code>x.__itruediv__(<var>y</var>)</code>. Se questo metodo è definito e restituisce un valore diverso da <code>NotImplemented</code>, abbiamo finito.
<li>Invocare <code>x.__truediv__(<var>y</var>)</code>. Se questo metodo è definito e restituisce un valore diverso da <code>NotImplemented</code>, il vecchio valore di <var>x</var> viene scartato e rimpiazzato dal valore restituito, esattamente come se aveste eseguito <code>x = x / y</code>.
<li>Invocare <code>y.__rtruediv__(<var>x</var>)</code>. Se questo metodo è definito e restituisce un valore diverso da <code>NotImplemented</code>, il vecchio valore di <var>x</var> viene scartato e rimpiazzato dal valore restituito.
</ol>
<p>Quindi avete bisogno di definire metodi in loco come il metodo <code>__itruediv__()</code> solo se volete effettuare qualche ottimizzazione speciale per l’operando in loco. Altrimenti, Python essenzialmente riformulerà l’operazione in loco in modo da utilizzare un operando normale più un assegnamento di variabile.
<p>Ci sono anche alcune operazioni matematiche “unarie” che gli oggetti simili a numeri possono eseguire su sé stessi.
<table>
<tr><th>Note
<th>Voi volete…
<th>Quindi scrivete…
<th>E Python invoca…
<tr><th>
<td>un numero negativo
<td><code class=pp>-x</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__neg__><code>x.<dfn>__neg__</dfn>()</code></a>
<tr><th>
<td>un numero positivo
<td><code class=pp>+x</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__pos__><code>x.<dfn>__pos__</dfn>()</code></a>
<tr><th>
<td>il valore assoluto
<td><code class=pp>abs(x)</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__abs__><code>x.<dfn>__abs__</dfn>()</code></a>
<tr><th>
<td>l’inverso
<td><code class=pp>~x</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__invert__><code>x.<dfn>__invert__</dfn>()</code></a>
<tr><th>
<td>un numero complesso
<td><code class=pp>complex(x)</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__complex__><code>x.<dfn>__complex__</dfn>()</code></a>
<tr><th>
<td>un numero intero
<td><code class=pp>int(x)</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__int__><code>x.<dfn>__int__</dfn>()</code></a>
<tr><th>
<td>un numero in virgola mobile
<td><code class=pp>float(x)</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__float__><code>x.<dfn>__float__</dfn>()</code></a>
<tr><th>
<td>un numero arrotondato all’intero più vicino
<td><code class=pp>round(x)</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__round__><code>x.<dfn>__round__</dfn>()</code></a>
<tr><th>
<td>un numero arrotondato alla <var>n</var>-sima cifra
<td><code class=pp>round(x, n)</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__round__><code>x.<dfn>__round__</dfn>(n)</code></a>
<tr><th>
<td>il più piccolo intero che sia <code>>= x</code>
<td><code class=pp>math.ceil(x)</code>
<td><a href=http://docs.python.org/3.1/library/math.html#math.ceil><code>x.<dfn>__ceil__</dfn>()</code></a>
<tr><th>
<td>il più grande intero che sia <code><= x</code>
<td><code class=pp>math.floor(x)</code>
<td><a href=http://docs.python.org/3.1/library/math.html#math.floor><code>x.<dfn>__floor__</dfn>()</code></a>
<tr><th>
<td>troncare <code>x</code> all’intero più vicino verso lo 0
<td><code class=pp>math.trunc(x)</code>
<td><a href=http://docs.python.org/3.1/library/math.html#math.trunc><code>x.<dfn>__trunc__</dfn>()</code></a>
<tr><th><span class=inherit><a href=http://www.python.org/dev/peps/pep-0357/><abbr>PEP</abbr> 357</a></span>
<td>usare un numero come indice di lista
<td><code class=pp>a_list[<var>x</var>]</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__index__><code>a_list[x.<dfn>__index__</dfn>()]</code></a>
</table>
<h2 id=rich-comparisons>Classi che possono essere confrontate</h2>
<p>Ho separato questa sezione dalla precedente perché i confronti non sono strettamente un privilegio dei numeri. Molti tipi di dato possono essere confrontati — stringhe, liste, persino dizionari. Se state creando una vostra classe e ha senso confrontare i vostri oggetti con altri oggetti, potete usare i metodi speciali che seguono per realizzare i confronti.
<table>
<tr><th>Note
<th>Voi volete…
<th>Quindi scrivete…
<th>E Python invoca…
<tr><th>
<td>uguaglianza
<td><code class=pp>x == y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__eq__><code>x.<dfn>__eq__</dfn>(<var>y</var>)</code></a>
<tr><th>
<td>disuguaglianza
<td><code class=pp>x != y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__ne__><code>x.<dfn>__ne__</dfn>(<var>y</var>)</code></a>
<tr><th>
<td>minore di
<td><code class=pp>x < y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__lt__><code>x.<dfn>__lt__</dfn>(<var>y</var>)</code></a>
<tr><th>
<td>minore o uguale a
<td><code class=pp>x <= y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__le__><code>x.<dfn>__le__</dfn>(<var>y</var>)</code></a>
<tr><th>
<td>maggiore di
<td><code class=pp>x > y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__gt__><code>x.<dfn>__gt__</dfn>(<var>y</var>)</code></a>
<tr><th>
<td>maggiore o uguale a
<td><code class=pp>x >= y</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__ge__><code>x.<dfn>__ge__</dfn>(<var>y</var>)</code></a>
<tr><th>
<td>un valore di verità in un contesto logico
<td><code class=pp>if x:</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__bool__><code>x.<dfn>__bool__</dfn>()</code></a>
</table>
<blockquote class=note>
<p><span class=u>☞</span>Se definite un metodo <code>__lt__()</code> ma non definite un metodo <code>__gt__()</code>, Python userà il metodo <code>__lt__()</code> con gli operandi invertiti. Tuttavia, Python non combinerà i metodi. Per esempio, se definite un metodo <code>__lt__()</code> e un metodo <code>__eq__()</code> e provate a verificare se <code>x <= y</code>, Python non invocherà <code>__lt__()</code> e <code>__eq__()</code> in sequenza, ma invocherà soltanto il metodo <code>__le__()</code>.
</blockquote>
<h2 id=pickle>Classi che possono essere serializzate</h2>
<p>Python supporta <a href=serializzare-oggetti-python.html>la serializzazione e la deserializzazione di oggetti arbitrari</a>. (La maggior parte del materiale di consultazione su Python chiama questi processi “pickling” e “unpickling”.) La serializzazione può rivelarsi utile per salvare lo stato di un oggetto su un file e ripristinarlo successivamente. Tutti i <a href=tipi-di-dato-nativi.html>tipi di dato nativi</a> includono già il supporto per la serializzazione. Se create una classe che volete essere in grado di serializzare, vi suggerisco di leggere la documentazione sul <a href=http://docs.python.org/3.1/library/pickle.html>protocollo di serializzazione</a> per vedere quando e come i metodi speciali che seguono vengono invocati.
<table>
<tr><th>Note
<th>Voi volete…
<th>Quindi scrivete…
<th>E Python invoca…
<tr><th>
<td>la copia di un oggetto
<td><code class=pp>copy.copy(x)</code>
<td><a href=http://docs.python.org/3.1/library/copy.html><code>x.<dfn>__copy__</dfn>()</code></a>
<tr><th>
<td>la copia in profondità di un oggetto
<td><code class=pp>copy.deepcopy(x)</code>
<td><a href=http://docs.python.org/3.1/library/copy.html><code>x.<dfn>__deepcopy__</dfn>()</code></a>
<tr><th>
<td>ottenere lo stato di un oggetto prima della serializzazione
<td><code class=pp>pickle.dump(x, <var>file</var>)</code>
<td><a href=http://docs.python.org/3.1/library/pickle.html#pickle-state><code>x.<dfn>__getstate__</dfn>()</code></a>
<tr><th>
<td>serializzare un oggetto
<td><code class=pp>pickle.dump(x, <var>file</var>)</code>
<td><a href=http://docs.python.org/3.1/library/pickle.html#pickling-class-instances><code>x.<dfn>__reduce__</dfn>()</code></a>
<tr><th>
<td>serializzare un oggetto (con un nuovo protocollo di pickling)
<td><code class=pp>pickle.dump(x, <var>file</var>, <var>protocol_version</var>)</code>
<td><a href=http://docs.python.org/3.1/library/pickle.html#pickling-class-instances><code>x.<dfn>__reduce_ex__</dfn>(<var>protocol_version</var>)</code></a>
<tr><th>*
<td>controllare come un oggetto viene creato durante la deserializzazione
<td><code class=pp>x = pickle.load(<var>file</var>)</code>
<td><a href=http://docs.python.org/3.1/library/pickle.html#pickling-class-instances><code>x.<dfn>__getnewargs__</dfn>()</code></a>
<tr><th>*
<td>ripristinare lo stato di un oggetto dopo la deserializzazione
<td><code class=pp>x = pickle.load(<var>file</var>)</code>
<td><a href=http://docs.python.org/3.1/library/pickle.html#pickle-state><code>x.<dfn>__setstate__</dfn>()</code></a>
</table>
<p>* Per ricreare un oggetto serializzato, Python deve prima creare un nuovo oggetto simile all’oggetto serializzato e poi impostare i valori di tutti gli attributi del nuovo oggetto. Il metodo <code>__getnewargs__()</code> controlla come l’oggetto viene creato, poi il metodo <code>__setstate__()</code> controlla come i valori degli attributi vengono ripristinati.
<h2 id=context-managers>Classi che possono essere usate in un blocco <code>with</code></h2>
<p>Un blocco <code>with</code> definisce un <a href=http://www.python.org/doc/3.1/library/stdtypes.html#typecontextmanager>contesto di esecuzione</a>; voi “entrate” nel contesto quando l’istruzione <code>with</code> viene eseguita e “uscite” dal contesto dopo che l’ultima istruzione nel blocco è stata eseguita.
<table>
<tr><th>Note
<th>Voi volete…
<th>Quindi scrivete…
<th>E Python invoca…
<tr><th>
<td>fare qualcosa di speciale quando entrate in un blocco <code>with</code>
<td><code class=pp>with x:</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__enter__><code>x.<dfn>__enter__</dfn>()</code></a>
<tr><th>
<td>fare qualcosa di speciale quando uscite da un blocco <code>with</code>
<td><code class=pp>with x:</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__exit__><code>x.<dfn>__exit__</dfn>(<var>exc_type</var>, <var>exc_value</var>, <var>traceback</var>)</code></a>
</table>
<p>Ecco come funziona l’idioma <code>with <var>file</var></code>.
<pre class=pp><code># estratto da io.py:
def _checkClosed(self, msg=None):
'''Internal: raise an ValueError if file is closed
'''
if self.closed:
raise ValueError('I/O operation on closed file.'
if msg is None else msg)
def __enter__(self):
'''Context management protocol. Returns self.'''
<a> self._checkClosed() <span class=u>①</span></a>
<a> return self <span class=u>②</span></a>
def __exit__(self, *args):
'''Context management protocol. Calls close()'''
<a> self.close() <span class=u>③</span></a></code></pre>
<ol>
<li>L’oggetto file definisce sia un metodo <code>__enter__()</code> che un metodo <code>__exit__()</code>. Il metodo <code>__enter__()</code> verifica che il file sia aperto: se non lo è, il metodo <code>_checkClosed()</code> solleva un’eccezione.
<li>Il metodo <code>__enter__()</code> dovrebbe quasi sempre restituire <var>self</var> — questo è l’oggetto che il blocco <code>with</code> userà per inoltrare gli accessi ad attributi e metodi.
<li>All’uscita dal blocco <code>with</code>, l’oggetto file viene automaticamente chiuso. In che modo? Invocando <code>self.close()</code> nel metodo <code>__exit__()</code>.
</ol>
<blockquote class=note>
<p><span class=u>☞</span>Il metodo <code>__exit__()</code> verrà sempre invocato, anche se un’eccezione viene sollevata all’interno del blocco <code>with</code>. In effetti, nel caso in cui un’eccezione venga sollevata, le informazioni su quella eccezione saranno passate al metodo <code>__exit__()</code>. Si veda la documentazione sui <a href=http://www.python.org/doc/3.1/reference/datamodel.html#with-statement-context-managers>gestori di contesto per l’istruzione <code>with</code></a> per maggiori dettagli.
</blockquote>
<p>Per ulteriori informazioni sui gestori di contesto, si veda <a href=file.html#with>Chiudere i file automaticamente</a> e <a href=file.html#redirect>Redirigere il canale standard di uscita</a>.
<h2 id=esoterica>Roba veramente esoterica</h2>
<p>Se sapete quello che state facendo, potete ottenere il controllo quasi completo su come le classi sono confrontate, su come gli attributi sono definiti e su quali tipi di classe sono considerati sottotipi della vostra classe.
<table>
<tr><th>Note
<th>Voi volete…
<th>Quindi scrivete…
<th>E Python invoca…
<tr><th>
<td>il costruttore di una classe
<td><code class=pp>x = MyClass()</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__new__><code>x.<dfn>__new__</dfn>()</code></a>
<tr><th>*
<td>il distruttore di una classe
<td><code class=pp>del x</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__del__><code>x.<dfn>__del__</dfn>()</code></a>
<tr><th>
<td>che solo uno specifico insieme di attributi sia definito
<td>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__slots__><code>x.<dfn>__slots__</dfn>()</code></a>
<tr><th>
<td>un valore di hash personalizzato
<td><code class=pp>hash(x)</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__hash__><code>x.<dfn>__hash__</dfn>()</code></a>
<tr><th>
<td>ottenere il valore di una proprietà
<td><code class=pp>x.color</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__get__><code>type(x).<dfn>__dict__</dfn>['color'].__get__(x, type(x))</code></a>
<tr><th>
<td>impostare il valore di una proprietà
<td><code class=pp>x.color = 'PapayaWhip'</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__set__><code>type(x).<dfn>__dict__</dfn>['color'].__set__(x, 'PapayaWhip')</code></a>
<tr><th>
<td>eliminare una proprietà
<td><code class=pp>del x.color</code>
<td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__delete__><code>type(x).<dfn>__dict__</dfn>['color'].__del__(x)</code></a>
<tr><th>
<td>controllare se un oggetto è istanza della vostra classe
<td><code class=pp>isinstance(x, MyClass)</code>
<td><a href=http://www.python.org/dev/peps/pep-3119/#overloading-isinstance-and-issubclass><code>MyClass.<dfn>__instancecheck__</dfn>(x)</code></a>
<tr><th>
<td>controllare se una classe è sottoclasse di una vostra classe
<td><code class=pp>issubclass(C, MyClass)</code>
<td><a href=http://www.python.org/dev/peps/pep-3119/#overloading-isinstance-and-issubclass><code>MyClass.<dfn>__subclasscheck__</dfn>(C)</code></a>
<tr><th>
<td>controllare se una classe è sottoclasse di una vostra classe astratta di base
<td><code class=pp>issubclass(C, MyABC)</code>
<td><a href=http://docs.python.org/3.1/library/abc.html#abc.ABCMeta.__subclasshook__><code>MyABC.<dfn>__subclasshook__</dfn>(C)</code></a>
</table>
<p><sup>*</sup> Determinare esattamente quando Python invoca il metodo speciale <code>__del__()</code> è un’operazione <a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__del__>incredibilmente complicata</a>. Per capirla appieno, avete bisogno di sapere <a href=http://www.python.org/doc/3.1/reference/datamodel.html#objects-values-and-types>come Python tiene traccia degli oggetti in memoria</a>. Ecco un buon articolo <a href=http://www.electricmonk.nl/log/2008/07/07/python-destructor-and-garbage-collection-notes/>sulla garbage collection in Python e sulla sua relazione con i metodi distruttori di classe</a>. Dovreste anche leggere qualcosa sui <a href=http://mindtrove.info/articles/python-weak-references/>riferimenti deboli</a>, sul <a href=http://docs.python.org/3.1/library/weakref.html>modulo <code>weakref</code></a> e probabilmente, per sicurezza, anche sul <a href=http://www.python.org/doc/3.1/library/gc.html>modulo <code>gc</code></a>.
<h2 id=furtherreading>Letture di approfondimento</h2>
<p>Moduli menzionati in questa appendice:
<ul>
<li><a href=http://docs.python.org/3.1/library/zipfile.html>Il modulo <code>zipfile</code></a>
<li><a href=http://docs.python.org/3.1/library/cgi.html>Il modulo <code>cgi</code></a>
<li><a href=http://www.python.org/doc/3.1/library/collections.html>Il modulo <code>collections</code></a>
<li><a href=http://docs.python.org/3.1/library/math.html>Il modulo <code>math</code></a>
<li><a href=http://docs.python.org/3.1/library/pickle.html>Il modulo <code>pickle</code></a>
<li><a href=http://docs.python.org/3.1/library/copy.html>Il modulo <code>copy</code></a>
<li><a href=http://docs.python.org/3.1/library/abc.html>Il modulo <code>abc</code> (“Classi di Base Astratte”)</a>
</ul>
<p>Altre letture divertenti:
<ul>
<li><a href=http://www.python.org/doc/3.1/library/string.html#formatspec>Mini-linguaggio per le specifiche di formato</a>
<li><a href=http://www.python.org/doc/3.1/reference/datamodel.html>Modello dei dati di Python</a>
<li><a href=http://www.python.org/doc/3.1/library/stdtypes.html>Tipi built-in</a>
<li><a href=http://www.python.org/dev/peps/pep-0357/><abbr>PEP</abbr> 357: Fare in modo di poter affettare qualsiasi oggetto</a>
<li><a href=http://www.python.org/dev/peps/pep-3119/><abbr>PEP</abbr> 3119: Introduzione alle classi di base astratte</a>
</ul>
<p class=v><a rel=prev href=convertire-codice-verso-python-3-con-2to3.html title='indietro a “Convertire codice verso Python 3 con 2to3”'><span class=u>☜</span></a> <a rel=next href=dove-proseguire-da-qui.html title='avanti a “Dove proseguire da qui”'><span class=u>☞</span></a>
<p class=c>© 2001–10 <a href=informazioni-sul-libro.html>Mark Pilgrim</a><br>
© 2009–10 <a href=informazioni-sulla-traduzione.html>Giulio Piancastelli</a> per la traduzione italiana
<script src=j/jquery.js></script>
<script src=j/prettify.js></script>
<script src=j/dip3.js></script>