POO Herència

De Cacauet Wiki
La revisió el 21:54, 12 set 2012 per Enric (discussió | contribucions) (Es crea la pàgina amb «Herència és el mecanisme pel qual podem crear objectes (fills) que adopten les característiques d'un altre (pare) i que les extenen o sobreescriuen amb nous mètodes o…».)
(dif) ← Versió més antiga | Versió actual (dif) | Versió més nova → (dif)
Salta a la navegació Salta a la cerca

Herència és el mecanisme pel qual podem crear objectes (fills) que adopten les característiques d'un altre (pare) i que les extenen o sobreescriuen amb nous mètodes o atributs.

Herència bàsica

En Python la herència s'introdueix entre parèntesi. En aquest exemple Pilota() no hereda de ningú i PilotaDeTennis hereda les propietats (atributs i mètodes) de Pilota.

class Pilota():
   # ...veure definició més amunt...
class PilotaDeTennis(Pilota):
   color = "verd"
   def accelera(self):
      self.velocitat = self.velocitat + 12

Tinguem en compte que:

  • PilotaDeTenis hereda els atributs posx, posy i velocitat de Pilota.
  • Sobreescrivim el mètode accelera(), i enlloc d'accelerar 5 unitats (el mètode definit en Pilota), la PilotaDeTennis accelerarà 20 unitats.
>>> pelo = Pilota()
>>> ptennis = PilotaDeTennis()
>>> pelo.velocitat
10
>>> pelo.accelera()
>>> pelo.velocitat
15                          # Pilota ha accelerat 5 punts
>>> ptennis.velocitat
10
>>> ptennis.accelera()
>>> ptennis.velocitat
22                          # PilotaDeTennis ha accelerat 12 punts


"Noves classes" de Python

Llegir: http://docs.python.org/reference/datamodel.html#new-style-and-classic-classes

A partir de la versió 2.1 tots els objectes els heredem de "object". Es solventen alguns problemes antics. Es podria haver posat per defecte, però s'ha mantingut per la compatibilitat amb les aplicacions anteriors.

L' "estil antic" de classes Python (prèvies a 2.1) es defineixen:

class Pilota():
   ...

Ara, per definir un objecte "a la manera nova": OJU! sempre ho farem així en principi

class Pilota(object):
   ...

La diferència apreciable més important son els mètodes que heredem de "object":

>>> dir(Pilota)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__',
 '__getattribute__', '__hash__', '__init__', '__module__', '__new__',
 '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
 '__str__', '__subclasshook__', '__weakref__', 'accelera', 'posicio',
 'posx', 'posy', 'velocitat']


Constructoris i herència: instrucció super()

Quan creem una classe derivada i sobreescrivim el constructor (mètode __init__ en Python), el constructor del pare no es crida. Per exemple:

class A(object):
   def __init__(self):
      print "construint l'objecte..."

class B(A):
   def __init__(self):
      print "hola què tal?"

Ara comprovem què passa:

>>> a = A()
construint l'objecte...
>>> 
>>> b = B()
hola què tal?

Com podem veure, el constructor de A() no es crida al crear un objecte B(). Com que molt sovint es necessita cridar-lo, es pot fer amb la instrucció super(). Oju que aquest exemple és per Python 2.x. En Python 3.0 s'ha simplificat a super(), sense arguments, molt més elegant:

# exemple en Python 2.x
class A(object):
   def __init__(self):
      print "construint l'objecte..."

class B(A):
   def __init__(self):
      super(B,self).__init__()
      print "hola què tal?"

ULL!: si no creem l'objecte base A(object) heredat de "object", l'exemple no funcionarà.

Comprovem-ho:

>>> a = A()
construint l'objecte...
>>> b = B()
construint l'objecte...
hola què tal?



Herència múltiple

...


Polimorfisme

El polimorfisme és una important propietat de la POO, molt rellevant sobretot en llenguatges on no hi ha tipus dinàmics com el C++ o el Java. El què significa és que una referència (punter) a un objecte genèric (pare), al cridar a una funció que està sobrescrita per un objecte derivat, executarà la funció més "nova", és a dir, la de l'objecte instanciat realment.

El cas típic és tenir un array de punters a objectes pare que no sabem de quin tipus derivat exactament son, per exemple, un array de Pilotes. Segons com l'haguem creat, el punters apuntaran a objectes dels tiups PilotaDeTennis, PilotaDeFutbol i PilotaDeBasket, però no tenim perquè saber-ho, tot i que sabem segur que tots hereden de Pilota. Quan cridem al mètode accelera() s'executarà el de l'objecte derivat, no el del pare genèric, encara que el punter apunti a Pilota.

En el cas del Python no ens resulta molt rellevant ja que tenim tipus dinàmics amb total introspecció. Això vol dir que en tot moment sabem de quin tipus és cada objecte. A sobre, en Python podem tenir arrays d'objectes heterogenis, cosa que no es pot fer amb Java o C++. Així, el polimorfisme no en aquests llenguates és molt important, però no en Python.

Per saber més podeu llegir: