Python – Object Oriented

Pubblicità

Python è un linguaggio orientato agli oggetti da quando esiste. Per questo motivo, creare e usare classi e oggetti è facilissimo. Questo capitolo vi aiuta a diventare esperti nell’uso del supporto alla programmazione orientata agli oggetti di Python.

Se non avete alcuna esperienza precedente con la programmazione orientata agli oggetti (OO), potreste voler consultare un corso introduttivo o almeno un tutorial di qualche tipo in modo da avere una comprensione dei concetti di base.

Tuttavia, ecco una piccola introduzione alla Programmazione Orientata agli Oggetti (OOP) per mettervi al corrente –

Sopravvivenza della terminologia OOP

  • Classe – Un prototipo definito dall’utente per un oggetto che definisce un insieme di attributi che caratterizzano qualsiasi oggetto della classe. Gli attributi sono membri di dati (variabili di classe e variabili di istanza) e metodi, a cui si accede tramite la notazione punto.

  • Variabile di classe – Una variabile che è condivisa da tutte le istanze di una classe. Le variabili di classe sono definite all’interno di una classe ma al di fuori di qualsiasi metodo della classe stessa. Le variabili di classe non sono usate così frequentemente come le variabili di istanza.

  • Membro dei dati – Una variabile di classe o di istanza che contiene dati associati a una classe e ai suoi oggetti.

  • Overloading di funzione – L’assegnazione di più di un comportamento a una particolare funzione. L’operazione eseguita varia a seconda dei tipi di oggetti o argomenti coinvolti.

  • Variabile d’istanza – Una variabile che è definita all’interno di un metodo e appartiene solo all’istanza corrente di una classe.

  • Eredità – Il trasferimento delle caratteristiche di una classe ad altre classi che sono derivate da essa.

  • Instanza – Un oggetto individuale di una certa classe. Un oggetto obj che appartiene alla classe Circle, per esempio, è un’istanza della classe Circle.

  • Instanziazione – La creazione di un’istanza di una classe.

  • Metodo – Un tipo speciale di funzione che è definita nella definizione di una classe.

  • Oggetto – Un’istanza unica di una struttura dati che è definita dalla sua classe. Un oggetto comprende sia i membri dei dati (variabili di classe e variabili di istanza) che i metodi.

  • Operator overloading – L’assegnazione di più di una funzione ad un particolare operatore.

Creazione di classi

L’istruzione class crea una nuova definizione di classe. Il nome della classe segue immediatamente la parola chiave class seguita da due punti come segue –

class ClassName: 'Optional class documentation string' class_suite
  • La classe ha una stringa di documentazione, accessibile tramite ClassName.__doc__.

  • La class_suite consiste in tutte le dichiarazioni dei componenti che definiscono i membri della classe, gli attributi dei dati e le funzioni.

Esempio

Di seguito l’esempio di una semplice classe Python –

class Employee: 'Common base class for all employees' empCount = 0 def __init__(self, name, salary): self.name = name self.salary = salary Employee.empCount += 1 def displayCount(self): print "Total Employee %d" % Employee.empCount def displayEmployee(self): print "Name : ", self.name, ", Salary: ", self.salary
  • La variabile empCount è una variabile di classe il cui valore è condiviso tra tutte le istanze di questa classe. Vi si può accedere come Employee.empCount dall’interno della classe o dall’esterno della classe.

  • Il primo metodo __init__() è un metodo speciale, che è chiamato costruttore di classe o metodo di inizializzazione che Python chiama quando si crea una nuova istanza di questa classe.

  • Si dichiarano altri metodi di classe come normali funzioni con l’eccezione che il primo argomento di ogni metodo è self. Python aggiunge l’argomento self alla lista per voi; non avete bisogno di includerlo quando chiamate i metodi.

Creare oggetti istanza

Per creare istanze di una classe, chiamate la classe usando il nome della classe e passate qualsiasi argomento accettato dal suo metodo __init__.

"This would create first object of Employee class"emp1 = Employee("Zara", 2000)"This would create second object of Employee class"emp2 = Employee("Manni", 5000)

Accedere agli attributi

Si accede agli attributi dell’oggetto usando l’operatore punto con object. Si accede alla variabile di classe usando il nome della classe come segue –

emp1.displayEmployee()emp2.displayEmployee()print "Total Employee %d" % Employee.empCount

Ora, mettendo insieme tutti i concetti –

#!/usr/bin/pythonclass Employee: 'Common base class for all employees' empCount = 0 def __init__(self, name, salary): self.name = name self.salary = salary Employee.empCount += 1 def displayCount(self): print "Total Employee %d" % Employee.empCount def displayEmployee(self): print "Name : ", self.name, ", Salary: ", self.salary"This would create first object of Employee class"emp1 = Employee("Zara", 2000)"This would create second object of Employee class"emp2 = Employee("Manni", 5000)emp1.displayEmployee()emp2.displayEmployee()print "Total Employee %d" % Employee.empCount

Quando il codice precedente viene eseguito, produce il seguente risultato –

Name : Zara ,Salary: 2000Name : Manni ,Salary: 5000Total Employee 2

È possibile aggiungere, rimuovere o modificare gli attributi delle classi e degli oggetti in qualsiasi momento –

emp1.age = 7 # Add an 'age' attribute.emp1.age = 8 # Modify 'age' attribute.del emp1.age # Delete 'age' attribute.

Invece di usare le normali istruzioni per accedere agli attributi, potete usare le seguenti funzioni –

  • Il getattr(obj, name) – per accedere all’attributo dell’oggetto.

  • The hasattr(obj,name) – per controllare se un attributo esiste o no.

  • The setattr(obj,name,value) – per impostare un attributo. Se l’attributo non esiste, allora sarà creato.

  • Il delattr(obj, name) – per cancellare un attributo.

hasattr(emp1, 'age') # Returns true if 'age' attribute existsgetattr(emp1, 'age') # Returns value of 'age' attributesetattr(emp1, 'age', 8) # Set attribute 'age' at 8delattr(empl, 'age') # Delete attribute 'age'

Attributi di classe incorporati

Ogni classe Python mantiene i seguenti attributi incorporati e vi si può accedere usando l’operatore punto come qualsiasi altro attributo –

  • __dict__ – Dizionario contenente lo spazio dei nomi della classe.

  • __doc__ – Stringa di documentazione della classe o nessuna, se non definita.

  • __name__ – Nome della classe.

  • __module__ – Nome del modulo in cui la classe è definita. Questo attributo è “__main__” in modalità interattiva.

  • __bases__ – Una possibile tupla vuota contenente le classi base, nell’ordine in cui si presentano nella lista delle classi base.

Per la classe di cui sopra proviamo ad accedere a tutti questi attributi –

#!/usr/bin/pythonclass Employee: 'Common base class for all employees' empCount = 0 def __init__(self, name, salary): self.name = name self.salary = salary Employee.empCount += 1 def displayCount(self): print "Total Employee %d" % Employee.empCount def displayEmployee(self): print "Name : ", self.name, ", Salary: ", self.salaryprint "Employee.__doc__:", Employee.__doc__print "Employee.__name__:", Employee.__name__print "Employee.__module__:", Employee.__module__print "Employee.__bases__:", Employee.__bases__print "Employee.__dict__:", Employee.__dict__

Quando il codice di cui sopra viene eseguito, produce il seguente risultato –

Employee.__doc__: Common base class for all employeesEmployee.__name__: EmployeeEmployee.__module__: __main__Employee.__bases__: ()Employee.__dict__: {'__module__': '__main__', 'displayCount':<function displayCount at 0xb7c84994>, 'empCount': 2, 'displayEmployee': <function displayEmployee at 0xb7c8441c>, '__doc__': 'Common base class for all employees', '__init__': <function __init__ at 0xb7c846bc>}

Distruzione degli oggetti (Garbage Collection)

Python elimina automaticamente gli oggetti non necessari (tipi built-in o istanze di classe) per liberare lo spazio di memoria. Il processo con cui Python recupera periodicamente blocchi di memoria che non sono più in uso è chiamato Garbage Collection.

Il garbage collector di Python viene eseguito durante l’esecuzione del programma e viene attivato quando il numero di riferimenti di un oggetto raggiunge lo zero. Il conteggio dei riferimenti di un oggetto cambia quando cambia il numero di alias che puntano ad esso.

Il conteggio dei riferimenti di un oggetto aumenta quando gli viene assegnato un nuovo nome o viene messo in un contenitore (lista, tupla o dizionario). Il conteggio dei riferimenti dell’oggetto diminuisce quando viene cancellato con del, il suo riferimento viene riassegnato, o il suo riferimento va fuori portata. Quando il numero di riferimenti di un oggetto raggiunge lo zero, Python lo raccoglie automaticamente.

a = 40 # Create object <40>b = a # Increase ref. count of <40> c = # Increase ref. count of <40> del a # Decrease ref. count of <40>b = 100 # Decrease ref. count of <40> c = -1 # Decrease ref. count of <40> 

Normalmente non vi accorgerete quando il garbage collector distrugge un’istanza orfana e recupera il suo spazio. Ma una classe può implementare il metodo speciale __del__(), chiamato distruttore, che viene invocato quando l’istanza sta per essere distrutta. Questo metodo può essere usato per ripulire qualsiasi risorsa non in memoria usata da un’istanza.

Esempio

Questo distruttore __del__() stampa il nome della classe di un’istanza che sta per essere distrutta –

#!/usr/bin/pythonclass Point: def __init__( self, x=0, y=0): self.x = x self.y = y def __del__(self): class_name = self.__class__.__name__ print class_name, "destroyed"pt1 = Point()pt2 = pt1pt3 = pt1print id(pt1), id(pt2), id(pt3) # prints the ids of the obejctsdel pt1del pt2del pt3

Quando il codice precedente viene eseguito, produce il seguente risultato –

3083401324 3083401324 3083401324Point destroyed

Nota – Idealmente, dovresti definire le tue classi in un file separato, poi dovresti importarle nel tuo file principale del programma usando l’istruzione import.

Eredità delle classi

Invece di partire da zero, potete creare una classe derivandola da una classe preesistente elencando la classe padre tra parentesi dopo il nome della nuova classe.

La classe figlia eredita gli attributi della sua classe madre, e potete usare questi attributi come se fossero definiti nella classe figlia. Una classe figlia può anche sovrascrivere i membri dei dati e i metodi del genitore.

Sintassi

Le classi derivate sono dichiarate come la loro classe madre; tuttavia, una lista di classi base da cui ereditare è data dopo il nome della classe –

class SubClassName (ParentClass1): 'Optional class documentation string' class_suite

Esempio

#!/usr/bin/pythonclass Parent: # define parent class parentAttr = 100 def __init__(self): print "Calling parent constructor" def parentMethod(self): print 'Calling parent method' def setAttr(self, attr): Parent.parentAttr = attr def getAttr(self): print "Parent attribute :", Parent.parentAttrclass Child(Parent): # define child class def __init__(self): print "Calling child constructor" def childMethod(self): print 'Calling child method'c = Child() # instance of childc.childMethod() # child calls its methodc.parentMethod() # calls parent's methodc.setAttr(200) # again call parent's methodc.getAttr() # again call parent's method

Quando il codice sopra è eseguito, produce il seguente risultato –

Calling child constructorCalling child methodCalling parent methodParent attribute : 200

Simile, si può guidare una classe da più classi padre come segue –

class A: # define your class A.....class B: # define your class B.....class C(A, B): # subclass of A and B.....

Si possono usare le funzioni issubclass() o isinstance() per controllare le relazioni di due classi e istanze.

  • La funzione booleana issubclass(sub, sup) restituisce vero se la sottoclasse data sub è effettivamente una sottoclasse della superclasse sup.

  • La funzione booleana isinstance(obj, Class) restituisce vero se obj è un’istanza della classe Class o è un’istanza di una sottoclasse di Class

Sovrascrivere i metodi

Puoi sempre sovrascrivere i metodi della tua classe madre. Una ragione per sovrascrivere i metodi del genitore è che potresti volere funzionalità speciali o diverse nella tua sottoclasse.

Esempio

#!/usr/bin/pythonclass Parent: # define parent class def myMethod(self): print 'Calling parent method'class Child(Parent): # define child class def myMethod(self): print 'Calling child method'c = Child() # instance of childc.myMethod() # child calls overridden method

Quando il codice sopra è eseguito, produce il seguente risultato –

Calling child method

Metodi di sovraccarico delle basi

La seguente tabella elenca alcune funzionalità generiche che potete sovrascrivere nelle vostre classi –

Sr.No. Metodo, Descrizione & Chiamata d’esempio
1

__init__ ( self )

Constructor (con eventuali argomenti opzionali)

Chiamata d’esempio : obj = className(args)

2

__del__( self )

Distruttore, elimina un oggetto

Chiama di esempio : del obj

3

__repr__( self )

Rappresentazione della stringa valutabile

Chiamata di esempio : repr(obj)

4

__str__( self )

Rappresentazione stringa stampabile

Chiama campione : str(obj)

5

__cmp__ ( self, x )

Confronto oggetti

Chiamata di esempio : cmp(obj, x)

Overloading Operators

Supponiamo che abbiate creato una classe Vector per rappresentare vettori bidimensionali, cosa succede quando usate l’operatore più per aggiungerli? Molto probabilmente Python vi sgriderà.

Potresti, tuttavia, definire il metodo __add__ nella tua classe per eseguire l’addizione dei vettori e quindi l’operatore più si comporterebbe come previsto –

Esempio

#!/usr/bin/pythonclass Vector: def __init__(self, a, b): self.a = a self.b = b def __str__(self): return 'Vector (%d, %d)' % (self.a, self.b) def __add__(self,other): return Vector(self.a + other.a, self.b + other.b)v1 = Vector(2,10)v2 = Vector(5,-2)print v1 + v2

Quando il codice sopra viene eseguito, produce il seguente risultato –

Vector(7,8)

Data Hiding

Gli attributi di un oggetto possono essere visibili o meno fuori dalla definizione della classe. Dovete nominare gli attributi con un doppio prefisso di sottolineatura, e questi attributi non saranno direttamente visibili agli esterni.

Esempio

#!/usr/bin/pythonclass JustCounter: __secretCount = 0 def count(self): self.__secretCount += 1 print self.__secretCountcounter = JustCounter()counter.count()counter.count()print counter.__secretCount

Quando il codice sopra è eseguito, produce il seguente risultato –

12Traceback (most recent call last): File "test.py", line 12, in <module> print counter.__secretCountAttributeError: JustCounter instance has no attribute '__secretCount'

Python protegge questi membri cambiando internamente il nome per includere il nome della classe. Potete accedere a tali attributi come object._className__attrName. Se sostituite la vostra ultima linea come segue, allora funziona per voi –

.........................print counter._JustCounter__secretCount

Quando il codice sopra viene eseguito, produce il seguente risultato –

Leave a Comment

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *