Introducción Python Orientado a Objetos

Copyright (c) 2003 Eduardo Ferro Aldama bajo GNU FDL

Introducción

Python es un lenguaje interpretado orientado al desarrollo rápido de aplicaciones. Como podremos ver a continuación se trata de un lenguaje muy sencillo que además posee una extensa libreria de módulos que hacen que el desarrollo y mantenimiento de aplicaciones sea muy rápido. Es especialmente indicado para crear scripts, prototipos, aplicaciones de tamaño medio, o incluso para utilizarlo como lenguaje de extension de aplicaciones (puesto que es facilmente integrable en aplicaciones C/C++ o Java)

Pretendo dar unas nociones básicas del uso de este lenguaje para desarrollo de aplicaciones orientadas a objetos. Dado que la sintaxis es muy sencilla y fácil de leer (como vereis parece pseudocódigo) vamos a pasar directamente a ver ejemplos de como podemos usarlo.

Clases

class Barrio:
    def __init__(self, nombre, numeroHabitantes):
        self.__nombre = nombre
        self.__numeroHabitantes = numeroHabitantes

    def getNombre(self):
        return self.__nombre

    def getNumeroHabitantes(self):
        return self.__numeroHabitantes

El código anterior define la clase Barrio que esta compuesta por tres metodos, el constructor, getNombre y getNumeroHabitantes.
Los constructores en Python tienen que tener el nombre __init__, en este caso nuestro constructor crea dos atributos (__nombre y __numeroHabitantes) que utiliza para almacenar los parametros pasados. Todos los métodos deben tener como primer parametro la palabra reservada "self" que representa la instancia de la clase actual (igual que la palabra "this" en C++ o Java). En Python la palabra "self" es obligatoria y siempre hay que utilizarla para acceder a los atributos o incluso para llamar a un método de nuestra misma clase.

Los otros dos métodos definidos son simplemente métodos de acceso para los atributos de la clase.

Instancias

barrioNorte = Barrio("Norte", 10000)
barrioSur = Barrio("Sur", 4000)
Como podemos ver para crear instancias de una clase, es decir objetos basta con llamar al nombre de la clase como si se tratase de una función y asignar el resultado a una variable o atributo.
En el código anterior hemos creado dos objetos de la clase Barrio (barrioNorte y barrioSur).

Como habeis podido ver en Python no es necesario declarar las variables, o atributos antes de poder usarlos, basta con asignar algo a una variable. Ademas es debilmente tipado por lo que una variable puede contener cualquier tipo. Esto implica que tenemos que tener mucho cuidado de que parametros pasamos a un método, puesto que puede que el tipo del parametro que enviemos no sea el que el método espera por lo que se produciría un error en ejecución.

Ejemplo programa Python

#!/usr/bin/env python

class Barrio:
    def __init__(self, nombre, numeroHabitantes):
        # Asignamos valores a los atributos
        self.__nombre = nombre
        self.__numeroHabitantes = numeroHabitantes

    def getNombre(self):
        return self.__nombre

    def getNumeroHabitantes(self):
        return self.__numeroHabitantes
    

def main():
    # creamos dos objetos de la clase 
    # Barrio
    barrioNorte = Barrio("Norte", 10000)
    barrioSur = Barrio("Sur", 4000)

    # Imprimimos el nombre asignado a los 
    # dos barrios
    print barrioNorte.getNombre()
    print barrioSur.getNombre()


main()
Si copiamos el codigo anterior en un fichero (por ejemplo Barrio.py) y le damos permisos de ejecucion (chmod u+x nombreFichero) podemos ejecutar el fichero desde la linea de comandos de linux como si se tratase de un script de shell. La primera linea define que interprete se debe usar, el resto del ejemplo es el codigo Python a interpretar.
Los ficheros Python pueden tener cualuquier extensión pero es recomendable ponerle la extensión .py.

En este ejemplo hemos introducido algunos conceptos nuevos: Por una parte hemos introducido comentarios, python considera comentario desde el caracter "#" hasta el final de la línea.
Por otra parte hemos definido una función llamada main a la que llamamos al final del fichero.
Python interpreta el fichero de arriba a abajo y ejecuta todo el código que encuentre fuera de funciones o clases. En este caso el único código que se encuentra fuera de una función o de la definición de una clases es la llamada a la función main por lo que cuando interpretemos este fichero se ejecutará la función main.
La función inicial se suele llamar main, pero no es obligado usar ese nombre.

Sintaxis básica

Una vez que ya hemos visto algunos ejemplos vamos a pasar a comentar la sintaxis básica del lenguaje:

Tipos básicos

Python cuenta con tipos básicos para enteros, decimales y cadenas, pero hasta la versión 2.3 no tenía tipo booleano, hasta esa versión se consideraba valor verdadero cualquier cosa distinta de 0.
Además Python cuenta con contenedores de los que podemos destacar las listas, las tuplas y los diccionarios (mapas).
A continuación describimos estos tres contenedores: Estos tres tipos de contenedores permiten almacenar cualquier combinación de objetos de forma que podemos tener listas que mezclen números, cadenas y objetos, o diccionarios que como clave tienen un objeto y como valor una lista.
Todos los objetos se almacenan en los contenedores por referencia.

Estructuras de control

A continación ponemos ejemplos de las estructuras de control básicas de las que disponemos:
    
# Ejemplo 1
if barrio1.getNombre() == "Norte":
    print "Tratamiento barrio Norte"

# Ejemplo 2
if barrio1.getNombre() == "Norte":
    print "Tratamiento barrio Norte"
else:
    print "Tratmiento para otros barrios"

# Ejemplo 3
if barrio1.getNombre() == "Norte":
    print "Tratamiento barrio Norte"
elif barrio1.getNombre() == "Sur":
    print "Tratamiento barrio Sur"
else:
    print "Ni uno ni otro" 

   
# Ejemplo 4
listaNombres = ['Nombre1', 'Nombre2', 'Nombre3']
for nombre in listaNombres:
    print nombre

# Ejemplo 5
for numero in range(0, 5):
    print numero

# Ejemplo 6
encontradoFin = 0
n = 0
numeroIteraciones = 5
while not encontradoFin:
    if n == numeroIteraciones:
        encontradoFin = 1
    else:
        print "No encontrado Fin"
        n = n + 1
print "Encontrado fin"
Para los ejemplos del 1 al 3 debemos suponer que barrio1 es un objeto de la clase Barrio. Lo único que cabe destacar en estos primeros ejemplos es que en python no existe la estructura switch por lo que para encadenar diferentes opciones se usa la estructura del ejemplo 3.
El ejemplo 4 introduce el concepto de lista, y luego itera por los elementos de la lista mediante un for. El ejemplo 5 hace lo mismo pero la lista es generada mediante la función interna range que genera listas de numeros a partir de un comienzo y un final (también permite definir el incremento entre los elementeos de la lista).
Por último el ejemplo 5 introduce otro tipo de bucle, en este caso utilizando un while.

Más Objetos (Herencia y polimorfismo)

#!/usr/bin/env python

class Vehiculo:
    def __init__(self, ruedas):
        self.__ruedas = ruedas
    
    def tocaBocina(self):
        print "Beep, Beep!!!"


class Coche(Vehiculo):
    def __init__(self, modelo):
        # llamamos al constructor de nuestro
        # padre
        Vehiculo.__init__(self, 4)
        self.__modelo = modelo

    def tocaBocina(self):
        print "Piiiiiii!!!"

class Bicicleta(Vehiculo):
    def __init__(self):
        # llamamos al constructor de nuestro
        # padre
        Vehiculo.__init__(self, 2)

    def tocaBocina(self):
        print "Ring, Ring!!!"


def main():
    listaVehiculos = []
    listaVehiculos.append(Coche("r9"))
    listaVehiculos.append(Vehiculo(3))
    listaVehiculos.append(Bicicleta())
    listaVehiculos.append(Coche("p205"))

    for vehiculo in listaVehiculos:
        vehiculo.tocaBocina()
    

main()
El ejemplo anterior define las clases Vehiculo, Coche y Bicicleta. La primera clase sirve como base para Coche y Bicicleta. En Python al definir una clase después del nombre de la clase se pone entre parentesis la clase o clases de las que hereda. Se permite la herencia multiple aunque es un recurso que se debe usar con cuidado.
Como podemos ver en el constructor de la clase Coche las llamadas a los constructores de nuestras clases padre no son automáticas sino que somos nosotros los que tenemos que hacer explicitamente la llamada.

Las tres clases definen un mismo método llamado tocaBocina, de forma que las clases derivadas sobreescriben el método de la base. Cuando el interprete necesita llamar a un método de un objeto busca la definicion del método en todo el árbol de herencia de la clase, empezando desde la clase especifica y subiendo por los antecesores. Esto significa que si se necesitase llamar al método tocaBocina en un objeto de una clase que no hubiese definido ese método, se intentaria buscar el método en cada uno de los antecesores de la clase, en caso de que ninguno de los ancestros hubiese definido ese método se produciría un error de ejecución.
Este tipo de comportamiento permite usar de forma polimórfica los objetos. Un ejemplo de esto es el recorrido de la lista de vehiculos donde por cada uno llamamos al método tocaBocina sin tener que preocuparnos de que tipo es cada uno de los vehiculos. Como podemos suponer el resultado de la ejecución del ejemplo es:

Piiiiiii!!!
Beep, Beep!!!
Ring, Ring!!!
Piiiiiii!!!

Detalles a tener en cuenta

Los objetos en python siempre son tratados por referencia, de forma que cuando pasamos un objeto a un método, no se realiza una copia del objeto sino que el método puede interactuar con el objeto inicial. Al igual que en Java, existe un recolector de basura que se encarga de destruir los objetos que ya no sean referenciados desde ninguna parte de forma que el programador no se tenga que preocupar por la destrucción de los objetos y la gestión de la memoria.

En Python todos los métodos y atributos son publicos por defecto, para hacerlos privados debemos hacer que comiencen por __. En realidad esto no los hace exactamente privados pero impide el uso normal de los mismos desde fuera de la clase donde se declaran

Conclusiones

Python resulta un lenguaje muy eficaz para desarrollo rápido de aplicaciones, prototipos y scripts. La experiencia ha demostrado que también es un lenguaje apto para creación de aplicaciones de tamaño considerable. Su curva de aprendizaje es muy corta por lo que un programador puede dominarlo en poco tiempo.

Referencias


Si quieres ponerte en contacto conmigo:

eferro@inicia.es