"Linux Gazette... haciendo de Linux algo un poco más divertido!"


Una introducción a la Programación Orientada a Objetos en Python

Por: Michael Orr
Traducción al Español por: Felipe Barousse
el día 3 de Agosto de 2000 para La Gaceta de Linux

Alguien preguntó a Michael Williams si podría hacer las versiones para Python y Java de su artículo: Una introducción a la programación Orientada a Objectos en C++. Aquí está una versión en Python del código. Comentaré respecto a las diferencias entre C++ y Python. ¿ Tal vez alguien pueda escribir la versión de Java ?

Estoy asumiendo que el lector sabe los fundamentos básicos de Python. Si no, ver el excelente Tutorial y otra documentación en http://www.python.org/doc/.

Casas y más casas.

Para representar la casa de Michael (en la sección Classy! en el artículo de C++), podemos usar el siguiente código: (versión texto original)

#! /usr/bin/python
"""house.py -- Un programa de casas
Esta es un comentario, delimitado por tiples comillas.
"""

class House:
        pass

my_house = House()
my_house.number = 40
my_house.rooms = 8
my_house.garden = 1

print "Mi casa tiene el número", my_house.number
print "ésta tiene", my_house.rooms, "habitaciones"
if my_house.garden:
        garden_text = "tiene"
else:
        garden_text = "no tiene"
print "Esta", garden_text, "un jardin"

Al ejecutarse éste programa imprime ésto:

Mi casa tiene el número 40
ésta tiene 8 habitaciones
ésta tiene un jardin

¿Que hace éste programa? Primero, definimos que es una "casa" genérica en el bloque class. pass significa "no hacer nada" y es requerido si el bloque estará vacio. Entonces creamos una instancia (esto es, una casa en particular) por medio de una llamada al nombre de la clase como si fuera una función. La casa es entonces guardada en la variable my_house.

Esta casa inicialmente no tiene atributos, -si hiciéramos una consulta del valor de my_house.number antes de asignarlo, obtendríamos un AttributeError. Las siguientes tres líneas asignan y crean los atributos. Esta es una diferencia entre los lenguajes: Las instancias de Java inician con ciertos atributos los cuales nunca pueden cambiar (aún cuando sus valores si pueden hacerlo), sin embargo las instancias de Python inician sin atributos y se puede agregar o borrar atributos (o cambiar su tipo) mas tarde. Esto permite que Python sea más flexible en ciertas situaciones dinámicas.

Podemos inicializar la instancia al momento de su creación por medio de la inclusión del método especial __init__ . (Un método es una función que "pertenece" a una clase). Este programa: (versión texto original)

#! /usr/bin/python
"""house2.py -- Otra casa.
"""

class House:
        def __init__(self, number, rooms, garden):
                self.number = number
                self.rooms = rooms
                self.garden = garden

my_house = House(20, 1, 0)

print "Mi casa es la número", my_house.number
print "ésta tiene", my_house.rooms, "habitaciones"
if my_house.garden:
        garden_text = "tiene"
else:
        garden_text = "no tiene"
print "ésta", garden_text, "un jardín"

imprime:

Mi casa es la número 20
ésta tiene 1 habitaciones
ésta no tiene un jardín

Debido a que la clase tiene un método __init__ , es llamado de manera automática cuando la instancia es creada. Los argumentos de House son en realidad los argumentos para __init__. Aun cuando la mayoría de los progamas no lo hacen, se puede llamar a __init__ directamente cuantas veces se quiera: my_house.__init__(55, 14, 1). Esto le indica al objecto que se "reinicialize a si mismo".

Ha de notarse que __init__ es definido con un primer argumento extra, self. Pero no especificamos self cuando llamamos al método. Todos los métodos de Python trabajan así. self es de hecho la instancia en sí misma que Python provee tras bambalinas. Se necesita self porque es la única manera en que el método puede acceder a los atributos de las instancias y a otros métodos. Dentro del método, self.rooms se refiere al atributo de la instancia rooms, pero rooms se refiere a la variable local rooms. Las variable locales, por supuesto, se desvanecen cuando el método termina. El uso que hace Python de self tiene paralelo en Perl y también en otros lenguajes Orientados a Objectos.

Michael no lo dijo, pero C++ tiene el apuntador this el cual funciona como el self de Python. Ahora, en C++ no es neceario escribir this->house si es que no hay una variable local house, y nunca se escribe this en la línea de definición de un método. En otras palabras , C++ (y Java) hacen la misma cosa que Python y Perl; éstos solo que lo ocultan al programador.

De hecho, self en Python es sólo un nombre convencional. Puedes llamarlo this o me alternativamente si tu quieres. Personalmente a mi me gusta mas me. Sin embargo, me quedo con self por si alguien tiene que mantener mi trabajo después, le será más facil leerlo y entenderlo. Por contraste, la variable this de C++ es mágíca y no puede cambiársele el nombre.

En el programa en C++, garden es un atributo booleano. Python no tiene atributos booleanos así que usamos un entero en su lugar. La expresión my_house.garden es verdadera si el atributo es 1 (u otro valor diferente de cero o valor no vacio).

No seas cuadrado.

Esta sección corresponde a la sección de "Funciones de Miembros" en el artículo de Williams. Yo prefiero el término "método" sobre "funciones de miembros", como los Pythoneros usualmente lo hacen. El programa de Michael square.c se vería de ésta manera: (versión texto original)

#! /usr/bin/python
"""square.py -- Haz algunos ruidos al respecto del cuadrado.
"""

class Square:
        def __init__(self, length, width):
                self.length = length
                self.width = width

        def area(self):
                return self.length * self.width

my_square = Square(5, 2)
print my_square.area()

imprime

10

area debe ser explícito por si mismo debido a que opera exactamente igual que el __init__ de arriba. Para reiterar, todos los selfs en square.py son requeridos. He escogido dar al programa Square un método __i n it__ en lugar de definir los atributos mas tarde debido a que eso es lo que la mayoría de los programadores de Python harian.

Definición de funciones afuera de la definición de la clase

Nada que decir al respecto. Python no permite métodos definidos fuera de una clase. Por supuesto, esto no aplica a las funciones ordinarias (que no son parte de una clase).

¿Publica o privada?

No mucho que decir aquí tampoco. Todos los atributos y métodos de Python son públicos. Se pueden emular atributos y métodos privados por vía del truco de la doble-subraya, sin emabargo la maypria de los programadores de Python no lo hacen. En su lugar, se cuenta con que el programador no abuse del API de la clase.

Constructores de clases

El método __init__ es el constructor.

Arreglos y clases

El ejemplo de Williams de arreglos no puede ser codificado literalmente por las diferencias que existen entre los lenguajes, pero una versión equivalente es: (version texto original)

#! /usr/bin/python
"""person.py -- Un ejemplo de una persona.
"""
class Person:
        def __init__(self, age, house_number):
                self.age = age
                self.house_number = house_number

alex = []
for i in range(5):
        obj = Person(i, i)
        alex.append(obj)

print "Alex[3] age is", alex[3].age
print

for alexsub in alex:
        print "Age is", alexsub.age
        print "House number is", alexsub.house_number

Esto imprime

Alex[3] age is 3

Age is 0
House number is 0
Age is 1
House number is 1
Age is 2
House number is 2
Age is 3
House number is 3
Age is 4
House number is 4                                                          

Python no tiene un equivalente a person alex[5] en el programa en C++ el cual crea un arreglo de cinco instancias vacias al mismo tiempo. En su lugar, creamos una lista vacia luego usamos un ciclo o bucle for (el cual define i a 0, 1, 2, 3 and 4 respectivamente) para llenarla. El ejemplo muestra un ciclo o bucle subscribiendo una lista por número de índice, otro bucle el cual selecciona cada elemento de la lista directamente y, una sentencia print que accesa un elemento por número de índice.


Copyright © 2000, Michael Orr
Publicado en el número 56 de Linux Gazette, Agosto 2000