Curso de Python: 8-Orientación a objetos

La orientación a objetos es un paradigma de programación en el que todo se conceptualiza como objeto, tal y como se realiza en el mundo real. De esta manera, tratar objetos es más natural y sencillo de entender que con código puro. En este curso no se trata de enseñar a fondo este paradigma, si no mostrar cómo Python trata dicho paradigma.

Clases
La orientación a objetos arranca con el concepto de una clase, que es como el molde o el modelo de un objeto. Una clase define las características comunes a cualquier objeto de ese tipo o clase. Estas características están clasificadas en propiedades (o atributos) y métodos (acciones o funciones). Por ejemplo, una clase Vehiculo define las propiedades (ruedas, color, ancho o alto) y los métodos (arrancar, acelerar o frenar) comunes a todos los vehículos.  
Una clase define las propiedades y los métodos comunes a los objetos

Para llevar a la práctica estos conceptos, crearemos el módulo Vehiculo.py, escribiendo el siguiente código:

class Vehiculo:

   """ La clase Vehiculo define las caracteristicas comunes de cualquier vehiculo."""
   ruedas=4
   color='Amarillo'
   ancho=170
   alto=140
   largo=400

   def __init__(self, aRuedas, aColor, aAncho, aAlto, aLargo):
      self.ruedas=aRuedas
      self.color=aColor
      self.ancho=aAncho
      self.alto=aAlto
      self.largo=aLargo

   def arrancar(self):
      print "Vehiculo arrancado"

   def acelerar(self):
      print "Acelerando vehiculo"

   def frenar(self):
      print "Frenando vehiculo"

Las propiedades de la clase se definen como variables a nivel de bloque, fuera de los métodos, y tienen visibilidad dentro y fuera de la clase. Las variables definidas dentro de cada método son propias del método, y no tienen visión fuera de este ámbito.

El método __init__ es especial para las clases, el cual se ejecuta automáticamente al crear el objeto. Es similar al constructor de otros lenguajes orientados a objetos.

El parámetro self es obligatorio en los métodos de la clase, el cual no se pasa cuando se le llama. Contiene una referencia al propio objeto, por lo que se utiliza para acceder a cualquier propiedad o método del propio objeto, como en el caso del método __init__, donde accede a las propiedades del propio objeto para asignarle los valores pasados por parámetro.

El texto inicial mediante comillas triples es un comentario especial. Sirve para documentar el módulo, a modo de ayuda.

Las clases son reutilizables, por lo que se pueden guardar en módulos, y organizando éstos en paquetes.


Instancias
Una clase es una definición genérica de un tipo de objetos. Una instancia es una entidad física de una clase, o, lo que es lo mismo: un objeto físico. Por ejemplo, mi propio coche es un objeto físico (o una instancia) de la clase Vehiculo. Aunque existan mil coches de la misma marca y del mismo modelo, cada uno de ellos es, en sí mismo, una entidad física única, y es tratado como objeto único e individual.
Una instancia es un objeto físico, único e individual, de un tipo o clase Para crear una instancia, se asigna a una variable el valor de la clase. Si se definió el método __init__ se pasarían los parámetros necesarios para que la instancia se inicialice con las propiedades correspondientes:

>>> from Vehiculo import *
>>> miCoche=Vehiculo(4,'Azul',170,155,420)
>>> print "Color de mi coche: ",miCoche.color
Color de mi coche: Azul
>>> miCoche.color = 'Rojo' # Cambio de color
>>> print "Color de mi coche: ",miCoche.color
Color de mi coche: Rojo
>>> miCoche.arrancar()
Vehiculo arrancado

El acceso a las características del objeto se realiza nombrando al objeto, seguido de un punto, y del nombre de la propiedad o del método. La función dir() obtiene las características que posee un objeto:

>>> dir(miCoche)
['__doc__', '__init__', '__module__', 'acelerar', 'alto', 'ancho', 'arrancar', 'color', 'frenar', 'largo', 'ruedas']

Se puede apreciar que incluye tres métodos especiales ya predefinicos: __doc__ (muestra la documentación o ayuda), __init__ (método constructor), __module__ (nombre del módulo).

>>> miCoche.__doc__
' La clase Vehiculo define las caracteristicas comunes\n\t\tde cualquier vehiculo.'
>>> miCoche.__module__
'Vehiculo'

La función especial dir también se aplica a los módulos normales, y permite conocer las funciones que se
han importado de dicho módulo.

Clases derivadas
Habrá ocasiones en que la complejidad de las clases será importante, y será necesario organizar la semántica de las clases de alguna manera, además de por paquetes. La orientación a objetos nos permite crear clases derivadas, que son clases que “derivan” las características de otra clase base y agrega nuevas características o modifica alguna existente. El concepto de derivación es igual que el de herencia.

Por ejemplo, si quisiéramos tener una clase para las motos, en lugar de tener que definir nuevamente todas las características de los vehículos, como una moto es un tipo de vehículo, se puede derivar de éste. La definición de una clase derivada es igual que la de una clase normal, pero a la hora de declarar la clase, se indica también de qué clase deriva. Para ver esto en la práctica, crearemos el módulo Moto.py, que contendrá el siguiente código:

from Vehiculo import *

class Moto(Vehiculo):
   """ La clase Moto deriva de la clase Vehiculo,
       especializando caracteristicas de la propia moto """
   marcha=0

   def __init__(self, aColor):
      self.ruedas=2
      self.marcha=0
      self.color=aColor

   # Sobreescribe metodo arrancar()
   def arrancar(self):
      print "Moto arrancada"

   def cambiarMarcha(self, aMarcha):
      self.marcha=aMarcha

A la hora de instanciar de esta clase, se procede como si fuera una clase normal:

>>> from Moto import *
>>> miMoto=Moto("Roja")
>>> miMoto.ruedas
2
>>> miMoto.color
'Roja'
>>> miMoto.arrancar() # de clase Moto
Moto arrancada
>>> miMoto.cambiarMarcha(3)
>>> print "Ahora voy en la marcha",miMoto.marcha
Ahora voy en la marcha 3
>>> miMoto.acelerar() # de clase Vehiculo
Acelerando vehiculo

No existen limitaciones en cuanto al nivel de derivación. A un nivel más profundo, una clase derivada derivaría las características de su clase base, y si ésta derivase de otra superior, también derivaría las características de ésta, y así hasta el primer nivel de derivación.

Cuando se accede a una propiedad o a un método desde una instancia de una clase derivada, primero se busca en la propia clase derivada. Si no se encuentra allí, buscaría en la clase base inmediatamente superior. Y así, hasta la clase base de primer nivel.

Herencia múltiple
Una clase puede derivar de varias clases base.

class Quad(Moto, Coche):
   <sentencia-1>
   …
   <sentencia.n>

El acceso a una característica se realiza de forma similar a la de una clase derivada normal. Primero busca en la clase derivada. Si no se encuentra, busca en la jerarquía de las clases base de izquierda a derecha, hasta el primer nivel de derivación: primero Moto (y Vehiculo) y después Coche (y Vehiculo)

Una clase derivada hereda las características de sus clases bases en todos sus niveles jerárquicos

Entregas:

Enlaces de interés:

© commandcat
Maira Gall