Aprenent Python Recorrent el camí pas a pas

37 Herència

El contingut està agafat de la font per raons de coherència en l’aprenentatge el posem explícitamen en aquest artícle. Tot el mèrit de composició està en la font, al final del document.

1. Introducció al concepte

Un dels principals avantatges de la programació orientada a objectes és la reutilització de codi. Una de lesmaneres en que es pot aconseguir és mitjançant el mecanisme de l’herència. Una manera clara d’entendre l’herència és veure-la com la implementació de la relació entre tipus i subtius entre classes.


Suposem que volem escriure un programa que ha de guardar informació dels professors i alumnes d’una escola. Tant els professors com els alumnes comparteixen característiques en comú com ara el nom, l’edat i l’adreça. Per altra banda també tenen característiques específiques. Per exemple, els professors tenen un sou i imparteixen unes classes, mentre que els alumnes tenen notes.


Podriem crear dues classses independents per cadascun dels dos tipus. Això implicaria que afegir una nova característica comú requeriria fer-ho amb totes dues classes. A mida que els problemes es fan més complexox, això es torna immnanejable.

Es podria fer millor creant una classe anomenada Persona i fer després que les classes Professor i Alumne hereden d’aquesta classe. És a dir, les persones passarien a ser subtiups de la primera. Així, només caldria afegir les caractarístiques particulars dels subtipus.

La classe Persona en aquest context seria una classe base o superclase. Les classes Professor i Alumne serien classes derivades o subclasses.

2. Avantatges

  • Si canviem o afegim funcionalitats a la classe Persona, automàticament aquestes es reflecteixen en els seus subtipus. Per exemple, podriem afegir un no número d’identificació tant per als professors com per als alumnes. Només caldria afegir-lo a la classe Persona.
  • Els canvis que es fan en un dels subtipus no afecten a la resta dels subtipus.
  • Podem referir-nos als objectes de professors i alumnes com a objectes de persona, cosa que pot ser útil en algunes situacions, com comptar el nombre de persones que hi ha a l’escola. Això es coneix com a polimorfisme.
Polimorfisme

Es produix quan una sublasse pot ser substituïda a qualsevol situació on s’espere la superclasse. És a dir, l’objecte pot ser tractat com si fos una istància de la superclasse.

És a dir que reutilitzem el codi de la superclasse, i no ens cal repertir-ho a cada subclasse, a diferència del que hagués passat si ho haguéssem resolt amb classes independents.

3. Herència en un exemple

Codi

#!/usr/bin/python
# Filename: inherit.py

class Persona:
	'''Representa qualsevol membre de l'escola.'''
	def __init__(self, nom, edat):
		self.nom = nom
		self.edat = edat
		print '(Inicialitzada la Persona: %s)' % self.nom
	
	def tell(self):
		'''Mostra els detalls.'''
		print 'Nom:"%s" Edat:"%s"' % (self.nom, self.edat),

class Professor(Persona):
	''' Representa un professor.'''
	def __init__(self, nom, edat, sou):
		Persona.__init__(self, nom, edat)
		self.sou = sou
		print '(Inicialitzat el Professor: %s)' % self.nom

	def tell(self):
		Persona.tell(self)
		print 'Sou: "%d"' % self.sou

class Alumne(Persona):
	'''Representa un alumne.'''
	def __init__(self, nom, edat, notes):
		Persona.__init__(self, nom, edat)
		self.notes = notes
		print "(Inicialitzat l'Alumne: %s)" % self.nom
	
	def tell(self):
		Persona.tell(self)
		print 'Notes: "%d"' % self.notes

t = Professor('Mrs. Shrividya', 40, 30000)
s = Alumne('Swaroop', 22, 75)

# escriu una línia en blanc
print 

membres = [t, s]
for membre in membres:
	membre.tell() # funciona tant per professors com per estudiants

Eixida

$ python inherit.py
Inicialitzada la Persona: Mrs. Shrividya)
(Inicialitzat el Professor: Mrs. Shrividya)
(Inicialitzada la Persona: Swaroop)
(Inicialitzat l'Alumne: Swaroop)

Nom:"Mrs. Shrividya" Edat:"40" Sou: "30000"
Nom:"Swaroop" Edat:"22" Notes: "75"

Funcionament

Especifiquem els noms de les superclasses amb una tupla a continuació del nom de la classe a la definició d’aquesta. A continuació cridem explícitament el mètode __init__ de la superclasse fent la variable self. D’aquesta manera inicialitzem la part de l’objecte corresponent a la superclase.

És molt important recordar que Python no crida automàticament el constructor de la superclasse. Cal fer-ho explícitament.

Podem veure també que podem cridar els mètodes de la superclasse prefixant-los amb el nom d’squesta, i passant-li la variable self amb la resta dels arguments.

Podem tractar les instàncies de les classes Professor i Alumne com si foren instàncies e la classe Persona. Per exemple, quan fem servir el mètode tell de la classe Persona.

Finalment observem que el mètode tell que es crida és el de les subclasses i no el de la classe Persona. Python sempre comença a cercar els mètodes a la classe. Si no pot trobar el mètode a la classe, llavors comença a mirar els mètodes pertanyents a les superclasses en l’ordre especificat per la tupla de la deficició de la classe.

Tupla d’herència

Si apareix més d’una classe a la tubpla d’herència, es diu que hi ha herència múltiple.

Font: A Byte of Python - Herència