appunti3s:creare_classi_e_funzioni_in_python
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revision | Next revisionBoth sides next revision | ||
appunti3s:creare_classi_e_funzioni_in_python [2018/10/18 21:55] – profpro | appunti3s:creare_classi_e_funzioni_in_python [2020/06/08 22:19] – external edit 127.0.0.1 | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ====== Creare classi e attributi ====== | ||
+ | >> indice: [[appunti3s: | ||
+ | |||
+ | ===== Introduzione ===== | ||
+ | Questa introduzione andrebbe letta da chi conosce come si usano e si scrivono le funzioni, ma non conosce come si usano gli oggetti e le classi. | ||
+ | |||
+ | Anche gli oggetti, come le funzioni, sono pezzi di programma che possono essere riutilizzati, | ||
+ | Immaginando che il programma sia un insegnante che interroga gli studenti, e che come prima cosa debba conoscere il nome dello studente: | ||
+ | * Un insegnante //orientato alle funzioni//, prenderebbe in mano il documento dello studente, per poter leggere il nome dal suo documento. | ||
+ | * {{ : | ||
+ | * Un insegnante //orientato agli oggetti//, chiederebbe gentilmente allo studente di fornirgli il proprio nome. | ||
+ | * {{ : | ||
+ | |||
+ | Il primo insegnante, rispetto al secondo, agisce utilizzando un eccesso di forza e si comporta in modo sgarbato. Questo è il modo con cui si comporta una // | ||
+ | | ||
+ | |||
+ | Il secondo insegnante pensa che gli studenti abbiano diritto alla loro privacy e che inoltre sia più sicuro chiedere il nome invece che sperare di trovare, chissà in quale tasca, un documento. Anche il programmatore, | ||
+ | |||
+ | Ci sono anche altri vantaggi nell' | ||
+ | Per alcuni tipi di problemi la programmazione orientata agli oggetti invece non è la soluzione ideale.... | ||
+ | Di solito l' | ||
+ | Un po' come quando alcuni problemi si risolvono meglio usando la ricorsione e altri usando l' | ||
+ | |||
+ | ====Gli oggetti sono strumenti di lavoro==== | ||
+ | |||
+ | Gli oggetti sono strumenti che realizzano o forniscono qualcosa sui dati. | ||
+ | In questo modo si evita di occuparsi direttamente dei dati e si lascia che sia l' | ||
+ | |||
+ | ====Gli oggetti hanno una privacy==== | ||
+ | |||
+ | Gli oggetti sono responsabili dei propri dati, ma pretendono riservatezza. (vedere [[appunti3s: | ||
+ | |||
+ | >> Gli ogetti hanno una propria individualità, | ||
+ | |||
+ | ===== Terminologia ===== | ||
+ | |||
+ | La terminologia in Python è leggermente diversa da quella usata in Java o in C++ | ||
+ | |||
+ | * __classe__ = una categoria, un modello, un tipo di dato usato per creare oggetti. Una classe crea un namespace che contiene dati e funzioni. In Python, al termine della def di una classe, viene crato un //wrapper// (un astratto "// | ||
+ | * __l' | ||
+ | * un __attributo di classe__ è un dato appartenente all' | ||
+ | * un __metodo di classe__ è un oggetto-funzione appartenente all' | ||
+ | * __istanza__ = i comuni oggetti sono un' | ||
+ | * __attributi__ (dati e metodi) = tutto quello che viene dopo un punto (anche una funzione math.…). | ||
+ | * __attributo dato__ = sono le variabili di un particolare oggetto istanza. Vivono nel namespace dell' | ||
+ | * __attributo metodo__ = sono le funzioni di un particolare oggetto istanza. Vivono nel namespace dell' | ||
+ | * in Python è possibile rinominare i metodi (detti attributi metodi) perciò nella classe bisogna evitare conflitti di nome tra dati e funzioni. Si possono usare sostantivi per i primi e verbi per i secondi... | ||
+ | |||
+ | Nota: //self// non è una keyword del linguaggio Python, ma il suo uso è una vecchia consuetudine e cambiarla sarebbe poco utile... | ||
+ | |||
+ | ===== Namespace ===== | ||
+ | |||
+ | TO DO: Come si divide il codice in più file.py? | ||
+ | |||
+ | La keyword //global// si usa per definire oggetti globali (meglio usarla solo per le funzioni) | ||
+ | |||
+ | Come si possono definire nuovi namespace? Procedendo dal livello di accessibilità più esterno al più interno, possiamo definire un nuovo namespace usando un modulo, poi usando una classe e, infine, usando una funzione. | ||
+ | |||
+ | Come si possono creare nuovi oggetti locali? Instanziando nuovi oggetti oppure usando import. | ||
+ | |||
+ | Come si possono distruggere oggetti locali? Usando del. | ||
+ | |||
+ | ===== Visibilità ===== | ||
+ | |||
+ | Diversamente da altri linguaggi, come il C++, in Python **non** esistono specificatori di accesso (public, | ||
+ | |||
+ | ===== Esempi ===== | ||
+ | |||
+ | Ricordate la suddivisione tra programmatori e sviluppatori? | ||
+ | |||
+ | ==== Esempio 1 ==== | ||
+ | |||
+ | Siamo degli **sviluppatori** e dobbiamo preparare le librerie che verranno usate dal programmatore in un programma che conterrà il catalogo di un negozio di auto usate. Si deve descrivere ogni caratteristica dei veicoli: targa, kilometraggio, | ||
+ | Queste descrizioni sono gli //attributi dato// che sono contenuti dentro //oggetti// nella memoria del computer. Tali oggetti sono creati tutti a partire dallo stesso modello: la classe Auto. | ||
+ | |||
+ | Questa classe servirà al futuro **programmatore** per creare, ogni volta che serve, un oggetto auto. | ||
+ | Il programmatore, | ||
+ | < | ||
+ | Ora nella memoria del computer c'è una auto, ma è strana perché non si conosce nulla di quest' | ||
+ | Come può il futuro programmatore memorizzare la targa, il prezzo e i restanti attributi di questa auto? Li può specificare tra parentesi in questo modo: | ||
+ | < | ||
+ | |||
+ | Ciò deve essere previsto dallo sviluppatore, | ||
+ | <file python auto.py> | ||
+ | class Auto: | ||
+ | """ | ||
+ | def __init__(self, | ||
+ | self.targa = targa | ||
+ | self.km = km | ||
+ | self.prezzo = prezzo | ||
+ | </ | ||
+ | |||
+ | %%__init__()%% è un //attributo metodo// (una funzione) che descrive gli //attributi dato// e la loro inizializzazione. È uno degli attributi metodo più importanti che lo sviluppatore deve preparare. Il programmatore lo usa (senza saperlo) ogni volta che crea un oggetto. | ||
+ | Notare che mentre la chiamata del metodo contiene 3 parametri, nella funzione %%__init__()%% ce ne sono 4... | ||
+ | Notare anche l' | ||
+ | |||
+ | ==== Esempio 2 da terminare ==== | ||
+ | |||
+ | Se vogliamo scrivere un programma per una banca che possa gestire i dati anagrafici dei clienti e i dati dei loro conti correnti, ci vorranno come minimo due classi: Cliente e ContoCorrente. | ||
+ | Queste due classi serviranno al programmatore per creare, ogni volta che serve, un oggetto cliente e un oggetto contocorrente. Dentro questi oggetti sarà possibile trovare i dati come nome e cognome del cliente e numero e saldo del conto corrente. Per ora trascuriamo il problema di conoscere a chi è intestato il conto... | ||
+ | |||
+ | Questi oggetti possono essere considerate delle strutture dove memorizzare i dati. | ||
+ | |||
+ | Il problema successivo è il seguente: come operare sui dati? Si può agire in due modi: | ||
+ | * lasciare operare il programmatore direttamente sui dati per mezzo di istruzioni di assegnazione, | ||
+ | * oppure, creare dei metodi che operino in sicurezza sui dati, tutte le volte che serve al programmatore, | ||
+ | |||
+ | La programmazione orientata agli oggetti di solito persegue la seconda strategia, e consiglia di nascondere i dati al programmatore (data hiding) per evitare che vi acceda direttamente (combinando qualche guaio). In Python non è possibile modificare la visibilità degli attributi degli oggetti, si può solo agire sul loro nome, aggiungendo due underscore _ . | ||
+ | |||
+ | Quindi nella classe devo avere: | ||
+ | * attributi dato (ma non si dichiarano) | ||
+ | * attributi metodo: def dell' | ||
+ | < | ||
+ | __numero_conto=int(0) | ||
+ | __saldo=float(0) | ||
+ | def __init__(self): | ||
+ | __numero_conto=int(0) | ||
+ | __saldo=float(0) | ||
+ | def versamento(self, | ||
+ | self.__saldo+=float(importo) | ||
+ | return __saldo | ||
+ | </ | ||
+ | <file python bind01.py> | ||
+ | # | ||
+ | |||
+ | class ContoCorrente: | ||
+ | """ | ||
+ | # gli attributi vanno cercati, perche' | ||
+ | # ad esempio , due attributi sono i due pulsanti | ||
+ | |||
+ | def __init__(self, | ||
+ | | ||
+ | frame = Frame(master, | ||
+ | # container bianco # e' una var. locale di una funzione | ||
+ | # non viene distrutta solo grazie ad un sistema di Tkinter | ||
+ | # che la mantiene in vita... | ||
+ | frame.bind("< | ||
+ | frame.pack() # deve essere l' | ||
+ | |||
+ | def say_click(self, | ||
+ | print " | ||
+ | |||
+ | # programma | ||
+ | |||
+ | root = Tk() # crea la finestra genitore | ||
+ | root.geometry(" | ||
+ | |||
+ | app = App(root) # crea altri elementi della finestra genitore | ||
+ | |||
+ | root.mainloop() # loop degli eventi eseguito fino alla chiusura | ||
+ | |||
+ | </ | ||
+ | |||
+ | |||
+ | |||
+ | ==== Esempio 3 da terminare ==== | ||
+ | < | ||
+ | #creare prima una finestra e usare questo metodo per aprire una finestra di dialogo | ||
+ | percorso = tkFileDialog.askopenfilename | ||
+ | </ | ||
+ | Applicazione con event | ||
+ | |||
+ | <file python bind01.py> | ||
+ | # | ||
+ | from Tkinter import * | ||
+ | |||
+ | # definire una classe App (di solito una sottoclasse) | ||
+ | # permette di personalizzare la finestra | ||
+ | |||
+ | class App: | ||
+ | """ | ||
+ | # gli attributi vanno cercati, perche' | ||
+ | # ad esempio , due attributi sono i due pulsanti | ||
+ | |||
+ | def __init__(self, | ||
+ | | ||
+ | frame = Frame(master, | ||
+ | # attributo dato: un container bianco | ||
+ | |||
+ | frame.bind("< | ||
+ | frame.pack() # deve essere l' | ||
+ | |||
+ | def say_click(self, | ||
+ | print " | ||
+ | |||
+ | # programma | ||
+ | |||
+ | root = Tk() # crea la finestra genitore | ||
+ | root.geometry(" | ||
+ | |||
+ | app = App(root) # crea altri elementi della finestra genitore | ||
+ | |||
+ | root.mainloop() # loop degli eventi eseguito fino alla chiusura | ||
+ | |||
+ | </ | ||
+ | |||
+ | Se inserisco due pulsanti nel frame, il frame si stringe e diventa invisibile... | ||
+ | |||
+ | Applicazione a finestra con costruttore personalizzato. | ||
+ | Tk ha il metodo destroy()?? Frame ha il metodo quit()?? | ||
+ | |||
+ | <file python hello2.py> | ||
+ | # | ||
+ | from Tkinter import * | ||
+ | |||
+ | # definire una classe App (di solito una sottoclasse) | ||
+ | # permette di personalizzare la finestra | ||
+ | |||
+ | class App: | ||
+ | """ | ||
+ | # gli attributi vanno cercati, perche' | ||
+ | # ad esempio , due attributi sono i due pulsanti | ||
+ | |||
+ | def __init__(self, | ||
+ | | ||
+ | frame = Frame(master, | ||
+ | # container ora invisibile per posizionare pulsanti | ||
+ | # e' una var. locale di una funzione (come button) | ||
+ | # non viene distrutta solo grazie ad un sistema di Tkinter | ||
+ | # che la mantiene in vita... | ||
+ | |||
+ | frame.bind("< | ||
+ | frame.pack() # deve essere l' | ||
+ | | ||
+ | self.buttonQuit = Button(frame, | ||
+ | self.buttonQuit.pack(side=LEFT) | ||
+ | self.buttonHello = Button(frame, | ||
+ | self.buttonHello.pack(side=LEFT) | ||
+ | |||
+ | def say_hello(self): | ||
+ | print "hello in the terminal!" | ||
+ | |||
+ | # programma | ||
+ | |||
+ | root = Tk() # crea la finestra genitore | ||
+ | root.geometry(" | ||
+ | |||
+ | app = App(root) # crea altri elementi della finestra genitore | ||
+ | |||
+ | root.mainloop() # loop degli eventi eseguito fino alla chiusura | ||
+ | |||
+ | </ |
appunti3s/creare_classi_e_funzioni_in_python.txt · Last modified: 2020/07/29 18:42 by profpro