Python – Fabricando objetos


Objetivo: presentar el concepto de Objeto o Instancia de una Clase en Python.

En el anterior artículo introdujimos las clases, auténticos pilares de la Programación Orientada a Objetos. Podemos pensar en ellas como diseños de moldes o plantillas para representar en Python (abstraer) una determinada realidad.

Aprendimos, por ejemplo, a modelar un coche:

class Coche:
    
    marca = ''
    modelo = ''
    color = ''
    numero_de_puertas = 0
    cuenta_kilometros = 0
    velocidad = 0
    arrancado = False

    def arrancar(self):
        if not self.arrancado:
            print('Roarrrr')
            self.arrancado = True
        else:
            # Dale al encendido estando el coche arrancado y escucha...
            print('Kriiiiiiiiiiicccc')
  
    def parar(self):
        self.arrancado = False
  
    def acelerar(self):
        if self.arrancado:
            self.velocidad = self.velocidad + 1

    def frenar(self):
        if self.velocidad > 0:
            self.velocidad = self.velocidad - 1

    def pitar(self):
        print('Bip Bip Bip')

    def consultar_velocimetro(self):
        return self.velocidad

    def consultar_cuenta_kilometros(self):
        return self.cuenta_kilometros

En la definición de clase nos encontramos sus características o atributos, que toman forma de variables (marca, modelo, color, etc…) y la funcionalidad propia de la clase o métodos, que nos indican qué cosas podemos hacer con ella, representados mediante funciones (arrancar(), acelerar(), frenar(), etc.).

Pero esto no es más que un esquema, un molde. Lo que queremos ahora es fabricar coches concretos, como un Seat León de cinco puertas o un Ford Fiesta de tres.

Al hecho de “fabricar” objetos a partir de un molde de clase se le denomina instanciar, y al producto obtenido se le conoce como instancias o, simplemente, objetos de esa clase.

De modo que vamos a asegurarnos que tenemos los conceptos claros: las clases son los moldes a los que recurrimos después para crear objetos concretos.

Para poner en marcha nuestra fábrica de coches virtual no necesitaremos una gran inversión en infraestructura y personal; nos bastará con ejecutar el intérprete de Python.

Para mayor comodidad, supongamos que hemos preparado ya todo el código con la definición de la clase Coche y lo hemos incluido en un fichero tal como coche.py.

La primera labor consistirá, por lo tanto, en ejecutar dicho código. En mi caso, lo abro en Idle y lo ejecuto con Run, pero tú puedes elegir cualquier otra forma de hacerlo. La cuestión es tener el intéprete interactivo con toda la definición de la clase cargada ya en memoria.

Comprobemos su existencia:

>>> Coche
<class '__main__.Coche'>

Para fabricar coches concretos necesitamos invocar a lo que se conoce como el constructor de clase, que se ocupará de crear el objeto en memoria. El rito para que haga acto de presencia es muy simple: basta con escribir el nombre de la clase seguido de un par de paréntesis.

Construyamos un primer coche:

>>> coche1 = Coche()

Típicamente los paréntesis los utilizaremos para definir valores iniciales del objeto. Más adelante, cuando presentemos el inicializador, aprenderás a usar esa característica.

Parémonos un instante a contemplar nuestra primera fabricación:

>>> coche1
<__main__.Coche object at 0x0234B7D0>

Lo que nos está diciendo el intérprete es que coche1 es un objeto de tipo Coche y está ubicado en la dirección de memoria 0x0234B7D0.

Cada objeto posee en Python un identicador único que podemos consultar con la función id():

>>> id(coche1)
37009360

En CPython, la implementación más común de Python, este identificador coincide con la dirección de memoria anterior, como podrás comprobar si te tomas la molestia de pasarlo a hexadecimal.

Ya que nos ha ido tan bien, probemos a fabricar un segundo automóvil:

>>> coche2 = Coche()

Aunque de la misma clase, se trata en efecto de un objeto diferente:

>>> id(coche2)
37634800

Para acceder a los atributos y métodos del objeto recurrimos a la notación punto, separando el nombre del objeto del atributo o método mediante un punto.

Establezcamos algunos atributos de coche1:

<code>>>> coche1.marca = "Seat"
>>> coche1.modelo = "León"
>>> coche1.color = "negro"

Y otros tantos de coche2:

coche2.marca = "Ford"
coche2.modelo = "Fiesta"
coche2.numero_de_puertas = 3

Esta forma de proceder, que puede parecer natural, no es la común. Tal como ya hemos apuntado, para dar valores iniciales a los objetos suele emplezarse la figura del inicializador, como veremos más adelante. Lo importante ahora es comprender bien el concepto.

Comprobemos los atributos de coche1:

>>> coche1.marca
'Seat'
>>> coche1.modelo
'León'
>>> coche1.color
'negro'
>>> coche1.numero_de_puertas
0
>>> coche1.cuenta_kilometros
0
>>> coche1.velocidad
0
>>> coche1.arrancado
False

Aprecia como los atributos que no hemos inicializado expresamente toman los valores que tenían en la definición de la clase.

Juguemos ahora un poco con los métodos, funciones que definen lo que podemos hacer con los objetos.

Traigamos a la palestra el primero de ellos. Lo reescribo aquí por comodidad:

    def arrancar(self):
        if not self.arrancado:
            print('Roarrrr')
            self.arrancado = True
        else:
            # Dale al encendido estando el coche arrancado y escucha...
            print('Kriiiiiiiiiiicccc')

El parámetro self, tal como explicamos en el artículo anterior, es obligatorio y debe figurar el primero en la declaración del método. Hace referencia al objeto en cuestión sobre el que se aplicará el método.

Para invocar el método, recurrirmos nuevamente a la notación punto, pasando entre paréntesis los argumentos que requiere el método en particular sin contar a self. Como en arrancar sólo existe self, a efectos prácticos es como si no tuviera ninguno:

>>> coche1.arrancar()
Roarrrr

Aunque no esté presente en la invocación, se está pasando implícitamente como self el nombre del método que llama a arrancar(), en este caso, coche1. Observa el código del método. Lo primero que hace es comprobar que el coche no está arrancado, en cuyo caso imprime “Roarrr”, cambiando a continuación el atributo arrancado a True. Verifiquemos que en efecto se ha realizado esto último:

>>> coche1.arrancado
True

Naturalmente, coche2 permanece completamente ajeno a estas operaciones, pues arrancar no ha actuado sobre él, sino sobre coche1. Comprobemos que sigue detenido:

>>> coche2.arrancado
False

Estando coche1 arrancado, si intentamos arrancarlo de nuevo obtendremos un chirriante y desagradable ruido propio de forzar el motor de arranque sin necesidad:

>>> coche1.arrancar()
Kriiiiiiiiiiicccc

Revisemos algunos métodos más de la definición de la clase Coche:

    def parar(self):
        self.arrancado = False
  
    def acelerar(self):
        if self.arrancado:
            self.velocidad = self.velocidad + 1

    def frenar(self):
        if self.velocidad > 0:
            self.velocidad = self.velocidad - 1

Experimentemos con ellos. Cada vez que aceleramos, la velocidad del vehículo se incrementa en una unidad:

>>> coche1.acelerar()
>>> coche1.velocidad
1
>>> coche1.acelerar()
>>> coche1.velocidad
2

Para detener el vehículo, primero lo frenamos completamente:

>>> coche1.frenar()
>>> coche1.frenar() # Al tener velocidad 2 aplicamos dos veces el método
>>> coche1.velocidad
0

Y, a continuación, sacamos la llave de contacto:

>>> coche1.parar()
>>> coche1.arrancado
False

Es muy importante que estudies con cuidado en estos ejemplos cómo hemos accedido desde los métodos a los atributos del objeto a través de self. En la siguiente lección, cuando presentemos el inicializador, le daremos a esta operatividad un carácter esencial.

Javier Montero Gabarró


Python – Fabricando objetos


El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)


El Club del Autodidacta


Consulta el índice completo de artículos relacionados con Python.

Python – El concepto de Clase

Objetivo: presentar en Python el concepto de clase, pilar sobre el que está construido todo el paradigma de la programación orientada a objetos.

Ha llegado el momento de que introduzcamos la Programación Orientada a Objetos en Python. Supondremos que esta es la primera vez que te acercas a esta metodología y que desconoces completamente o tienes nociones imprecisas de lo que son las clases y los objetos, de modo que comenzaremos por lo esencialmente básico para que no arrastres lagunas conforme el tema vaya adquiriendo más complejidad.

Por cuestiones de economía me he permitido autoplagiarme empleando los ejemplos, e incluso las mismas palabras, que utilicé en la introducción a la POO que escribí en la serie dedicada a Java. Naturalmente, nuestros caminos divergirán tan pronto como comencemos a picar código concreto en Python.

El tratamiento empleado por Python para la POO difiere de manera importante en algunos aspectos al utilizado en otros lenguajes como Java, C++ o C#. Aunque podríamos habernos acercado a este tema directamente de un modo más pythonista, he preferido que nuestros primeros pasos sean sólidos, apoyados en un marco conceptualmente universal, como el compartido por los lenguajes de programación anteriormente citados.

¿Preparado para una nueva manera de resolver problemas?

Voy a proponerte un sencillo juego. Sal a la calle, mira a tu alrededor y contempla el mundo de un modo particular.

Veo veo… ¿Qué ves?
Una cosita… ¿Y qué cosita es?

Para empezar, quiero que identifiques qué tipos de objetos ves…

Puedes, por ejemplo, encontrarte coches, bares, semáforos o personas, por citar sólo unos cuantos tipos. Date cuenta de que, cuando digo tipos de objetos, hablo de un modo conceptual y general. Si te resulta chocante referirte a una persona como un objeto, prueba a sustituir la expresión por tipos de entidades, en su lugar.

Tipo y clase son dos términos sinónimos, de modo que vamos a cambiar “tipos de objetos” por “clases de objetos”, aproximándonos un poco más al concepto que da pie al artículo de hoy.

¿Qué clases de objetos vemos? Coches, bares, semáforos, personas…

La siguiente transformación lingüística consiste en simplificar clases de objetos por simplemente clases:

¿Qué clases vemos? Coches, bares, semáforos, personas…

Y ahora sí, nos sumergimos plenamente en la terminología de la programación orientada a objetos:

Tenemos la clase Coche, la clase Bar, la clase Semáforo, la clase Persona

Poco interesan ahora los detalles concretos. No importa si esa persona es Marta, está en el bar “Casa Manolo”, si tiene un Seat Panda o si el semáforo está en rojo. Estamos pensando en términos clasificatorios.

Vamos a adentrarnos ahora en el interior de cada una de estas clases.

¿Cómo son los coches? ¿Qué características pueden diferenciar uno de otro?

Por ejemplo, podríamos indicar la marca, el modelo, el color, la cilindrada, etc.

A las características las vamos a denominar atributos, término muy utilizado en la programación orientada a objetos.

¿Qué atributos tiene la clase Bar?

Todo bar tiene un nombre, una ubicación, un estado (si está abierto o cerrado), una lista de precios,…

Como atributos de la clase Semáforo podríamos indicar su ubicación y estado (rojo, verde o ámbar).

La clase Persona podría definir como atributos el nombre, sexo, edad, estado civil, altura, etc.

A continuación pensemos en el comportamiento de estas clases. Preguntémonos qué cosas hacen, qué tipo de acciones pueden realizar.

Un coche puede arrancar, detenerse, girar a la izquierda, acelerar, frenar, encender sus luces. Un semáforo puede cambiar de estado. Un bar puede abrir, cerrar, servirte una cerveza, cobrarla, modificar la lista de precios. Una persona puede hablar, dormir, conducir un coche, tomarse una cerveza en un bar.

En terminología de la programación orientada a objetos, a estas funciones que determinan el comportamiento de una clase se las conoce como métodos.

Empleando un lenguaje puramente pythonista, tanto a los atributos como a los métodos aquí descritos se les conoce como simplemente atributos. Para diferenciar unos de otros, Python emplea el término atributos de datos para referirse a los datos característicos de la clase. No obstante, al menos mientras continuemos presentando los conceptos básicos, seguiremos distinguiendo aquí entre atributos y métodos.

Sabemos qué es una clase y que está compuesta de atributos y métodos. Nuestra labor ahora consistirá en modelar en Python estas clases.

Modelar no es otra cosa sino crear una abstracción que represente de algún modo una determinada realidad.

Para crear en Python la clase Coche comenzamos usando la palabra reservada class, seguida del nombre de la clase y del símbolo de dos puntos:

class Coche:
    instrucción 1
    instrucción 2
    ...
    instrucción n

La clase más simple de todas no haría nada:

class Coche:
    pass

La sentencia pass pasa completamente, no hace absolutamente nada. Es útil en contextos en los que se requiere la presencia de al menos una instrucción, hasta que la inspiración acuda y coloquemos código sustituto.

Típicamente, indentados en la definición, introduciremos los atributos y métodos de que consta la clase Coche.

El nombre Coche lo escribimos con la primera letra en mayúsculas, pues es práctica común entre la POO que los nombres de clases empiecen así.

Introduzcamos algunos atributos:

class Coche:

    marca = ''
    modelo = ''
    color = ''
    numero_de_puertas = 0
    cuenta_kilometros = 0
    velocidad = 0
    arrancado = False

Hemos utilizado, provisionalmente, valores iniciales para los atributos: la cadena vacía para los tipo string, cero para los numéricos y False para el booleano, pero podrían haber sido otros cualesquiera. En el momento en que comencemos a fabricar objetos de esta clase todos estos atributos podrán recibir su valor concreto y particular.

Definamos ahora los métodos de la clase Coche:

class Coche:
    
    marca = ''
    modelo = ''
    color = ''
    numero_de_puertas = 0
    cuenta_kilometros = 0
    velocidad = 0
    arrancado = False

    def arrancar(self):
        pass
  
    def parar(self):
        pass
  
    def acelerar(self):
        pass

    def frenar(self):
        pass

    def pitar(self):
        pass

    def consultar_velocimetro(self):
        pass

    def consultar_cuenta_kilometros(self):
        pass

Observa que los métodos se implementan exactamente igual que las funciones. Como tales, junto a la palabra clave def aparece el nombre del método seguido de unos paréntesis con la declaración de parámetros formales, finalizando con dos puntos e indentando el cuerpo del método a continuación. Al igual que las funciones ordinarias, los métodos podrán o no devolver un valor.

Fíjate en self, un parámetro que debe figurar siempre al comienzo de todo método. Su significado quedará completamente claro en el siguiente artículo, cuando expliquemos el concepto de Objeto. Por el momento, como primera toma de contacto, que te vaya sonando que self hace referencia al objeto concreto sobre el que se está invocando el método.

La elección de self como nombre del parámetro es arbitraria, podría servir cualquier otro término. Aquí nos sumaremos a la denominación favorita entre la comunidad pythonista.

Hemos rellenado el cuerpo de los métodos con la instrucción nula pass, pero seamos algo atrevidos y escribamos algo de código:

class Coche:
    
    marca = ''
    modelo = ''
    color = ''
    numero_de_puertas = 0
    cuenta_kilometros = 0
    velocidad = 0
    arrancado = False

    def arrancar(self):
        if not self.arrancado:
            print('Roarrrr')
            self.arrancado = True
        else:
            # Dale al encendido estando el coche arrancado y escucha...
            print('Kriiiiiiiiiiicccc')
  
    def parar(self):
        self.arrancado = False
  
    def acelerar(self):
        if self.arrancado:
            self.velocidad = self.velocidad + 1

    def frenar(self):
        if self.velocidad > 0:
            self.velocidad = self.velocidad - 1

    def pitar(self):
        print('Bip Bip Bip')

    def consultar_velocimetro(self):
        return self.velocidad

    def consultar_cuenta_kilometros(self):
        return self.cuenta_kilometros

Intenta comprender el código aunque aún no hayamos explicado la notación punto ni el uso de self. No te preocupes, en absoluto, si te surgen dudas, pues todo quedará claro en el siguiente artículo. Lo importante ahora es que te quedes con los conceptos de clase, atributo y método.

La siguiente podría ser una primera aproximación simple al modelado de una persona:

class Persona:
    
    sexo = ''
    nombre = ''
    edad = 0
    coche = Coche()   # El coche que conduce esa persona
  
    def saludar(self):
        print('Hola, me llamo', self.nombre)

    def dormir(self):
        print('Zzzzzzzzzzz')

    def obtener_edad(self):
        return self.edad

Fíjate en que uno de los atributos es precisamente de la clase Coche que acabamos de definir:

coche = Coche() # El coche que conduce esa persona

No confundas el nombre del atributo (coche, en minúsculas), con el nombre de la clase (Coche, con la primera en mayúsculas). Recuerda que para Python son identificadores distintos. Nuevamente, no te preocupes si no comprendes la sentencia, que hace mención a la construcción explícita de un objeto de tipo Coche. El propósito es simplemente ilustrar que entre los atributos de una clase, además de tipos comunes (números, strings, listas, etc…), pueden figurar objetos de cualquier clase, incluso de las creadas por nosotros mismos.

Te propongo como ejercicio que te entretengas modelando las otras clases indicadas al comienzo, u otras de tu elección, para asentar estos conceptos primarios.

Las entidades no tienen por qué ser tangibles, necesariamente. El siguiente código modela nuestras emociones:

class Emocion:
    emocion = ''
  
    def obtener_emocion(self):
        return self.emocion
    
    def cambiar_emocion(self, nueva_emocion):
        self.emocion = nueva_emocion

Observa el método cambiar_emocion(), que además de self define un nuevo parámetro.

En el próximo artículo explicaremos el concepto de Objeto, gracias al cual materializaremos nuestras clases en entidades concretas, coches rugientes, personas de carne y hueso o sentidas emociones. Hasta entonces, bienvenido al apasionante mundo de la programación orientada a objetos.

Javier Montero Gabarró


Python – El concepto de Clase


El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)


El Club del Autodidacta


Consulta el índice completo de artículos relacionados con Python.

Java: Un programa para probar las clases

lasecreObjetivo: desarrollar un programa completo en Java que permita poner a prueba las clases que hemos definido en los artículos anteriores.

Hagamos una breve recopilación de lo que llevamos hasta ahora: hemos definido los conceptos de clase y de objeto, pilares sobre los que se edifica la metodología de la programación orientada a objetos. Sabemos que las clases encapsulan atributos, elementos que indican las características de los objetos, y métodos, conjunto de funciones que definen su comportamiento. Aprendimos a crear objetos nuevos con new y mostramos cómo acceder a los atributos y métodos mediante la notación punto.

Definimos varias clases; entre ellas, Persona y Coche. Cada una reside en su propio fichero de código fuente .java y ha sido compilada en su respectivo fichero .class.

Va a entrar en escena una nueva clase que contendrá el programa principal desde el que probaremos la operatividad de las anteriores.

// ProbandoClases.java

public class ProbandoClases
{
  public static void main(String[] args)
  {
    // Aquí introduciremos el código para probar nuestras clases
  }
}

Esta nueva clase la mantendremos en el mismo directorio en el que se encuentran las restantes y en un fichero independiente denominado ProbandoClases.java. El nombre del fichero debe coincidir con el de la clase, teniendo en cuenta, además, que se diferencian las mayúsculas de las minúsculas.

La razón de ubicar el programa y las clases en el mismo directorio no es otra sino para tener acceso a ellas desde el programa principal. En breve, cuando definamos el concepto de paquete , veremos otros modos de definir las clases y agruparlas de un modo más práctico que facilite la reutilización de código entre programas diferentes. Todo a su momento; vayamos concepto a concepto.

Fíjate en el esqueleto del programa principal: es la misma estructura que presentamos en el Hola Mundo. Con lo que ya sabemos sobre las clases podemos aportar algo más de luz.

public class ProbandoClases

Olvídate por el momento del public. Si te das cuenta, el programa en sí mismo también es una clase, caracterizada por la palabra reservada class. Como tal, podrá tener también sus atributos y métodos.

Fíjate ahora en la siguiente línea:

public static void main(String[] args)

Dejemos el public static para otra ocasión. Lo que vemos después no es más sino la definición de un método, denominado main, que acepta una serie de parámetros entre paréntesis (de los que hablaremos a su debido momento), y que no devuelve ningún valor (void).

Todos los programas en Java han de disponer de un método llamado main, definido del mismo modo que en nuestro ejemplo. Es el punto donde comenzará la ejecución del programa.

Si has programado en C esto no te resultará muy sorprendente, pues en ese lenguaje de programación todo comienza en main también. Lo particular de Java, donde prácticamente todo es un objeto, es que main, en sí mismo, está encapsulado dentro de una clase.

Para que nos sirva de referencia y por comodidad, repito aquí el código de las clases Coche y Persona.

// Coche.java

class Coche
{
  String marca;
  String modelo;
  String color;
  int numeroDePuertas;
  int cuentaKilometros;
  int velocidad;
  boolean arrancado;
  
  void arrancar()
  {
    arrancado = true;
  }
  
  void parar()
  {
    arrancado = false;
  }
  
  void acelerar()
  {
    velocidad = velocidad + 1;
  }
  
  void frenar()
  {
    velocidad = velocidad - 1;
  }
  
  void pitar()
  {
    System.out.println("Piiiiiiiiiiiiiiiiii");
  }
  
  int consultarCuentaKilometros()
  {
    return cuentaKilometros;
  }
}

// Persona.java

class Persona
{
  char sexo;
  String nombre;
  int edad;
  Coche coche;
  
  void saludar()
  {
    System.out.println("Hola, me llamo " + nombre);
  }
  
  void dormir()
  {
    System.out.println("Zzzzzzzzzzz");
  }
  
  int obtenerEdad()
  {
    return edad;
  }
}

He numerado las líneas del código del programa principal para poder referenciarlas después en la explicación. Obviamente, esa numeración no debe aparecer en el fichero real.

1  public class ProbandoClases
2  {
3    public static void main(String[] args)
4    {
5      // Aquí introduciremos el código para probar nuestras clases
6      
7      Coche coche1 = new Coche();
8      Persona persona1 = new Persona();
9      Persona persona2 = new Persona();
10    
11    
12      coche1.marca = "Seat";
13      coche1.modelo = "Panda";
14      coche1.color = "Beige";
15      coche1.numeroDePuertas = 3;
16      coche1.cuentaKilometros = 215000;
17      coche1.velocidad = 0;
18      coche1.arrancado = false;
19    
20      persona1.sexo = 'F';
21      persona1.nombre = "Marta";
22      persona1.edad = 32;
23      persona1.coche = coche1;
24    
25      persona2.nombre = "Raimundo";
26        
27      System.out.println(coche1.marca);
28      System.out.println(coche1.modelo);
29      System.out.println(coche1.color);
30      System.out.println(coche1.numeroDePuertas);
31      System.out.println(coche1.cuentaKilometros);
32      System.out.println(coche1.velocidad);
33      System.out.println(coche1.arrancado);
34    
35      System.out.println(persona1.sexo);
36      System.out.println(persona1.nombre);
37      System.out.println(persona1.edad);
38      System.out.println(persona1.coche);
39      System.out.println(persona1.coche.marca);
40      System.out.println(persona1.coche.modelo);
41    
42      System.out.println(persona2.sexo);
43      System.out.println(persona2.nombre);
44      System.out.println(persona2.edad);
45      System.out.println(persona2.coche);
46    
47      coche1.arrancar();
48      System.out.println(coche1.arrancado);
49      coche1.acelerar();
50      System.out.println(coche1.velocidad);
51      coche1.acelerar();
52      System.out.println(coche1.velocidad);    
53      coche1.acelerar();
54      System.out.println(coche1.velocidad);    
55      coche1.frenar();
56      System.out.println(coche1.velocidad);    
57      coche1.frenar();
58      System.out.println(coche1.velocidad);    
59      coche1.frenar();
60      System.out.println(coche1.velocidad);
61      coche1.parar();
62      System.out.println(coche1.arrancado);
63      coche1.pitar();
64      coche1.consultarCuentaKilometros();
65    
66      persona1.saludar();
67      persona1.obtenerEdad();
68      persona2.saludar();
69      persona2.obtenerEdad();
70      persona1.dormir();
71      persona2.dormir();  
72    
73    }
74  }

Si no has modificado las clases y ya tienes los respectivos ficheros .class generados, sólo necesitarás compilar el nuevo fichero:

javac ProbandoClases.java

En caso contrario, si tienes que compilar todo, puedes proceder así:

javac *.java

Para ejecutar el programa, basta con invocar la máquina virtual Java facilitando el nombre de la clase que contiene al método main():

java ProbandoClases

Esta es la salida generada, numerada por mí también para seguir mejor la explicación:

1  Seat
2  Panda
3  Beige
4  3
5  215000
6  0
7  false
8  F
9  Marta
10  32
11  Coche@8814e9
12  Seat
13  Panda
14
15  Raimundo
16  0
17  null
18  true
19  1
20  2
21  3
22  2
23  1
24  0
25  false
26  Piiiiiiiiiiiiiiiiii
27  Hola, me llamo Marta
28      32
29  Hola, me llamo Raimundo
30      0
31  Zzzzzzzzzzz
32  Zzzzzzzzzzz

En las líneas 7-9 del programa nos ocupamos de la creación de los tres objetos con los que trabajaremos, un coche y dos personas. Observa cómo, en la misma instrucción, declaramos cada objeto y lo creamos.

Establecemos valores para los atributos de estos objetos en las líneas 12-25. Al contrario de lo que sucede con persona1, a quien le hemos definido todos sus atributos, persona2 sólo recibe valor (por nuestra parte) del nombre.

En 27-45 realizamos una impresión de todos los atributos de los tres objetos. Podemos observarlo en las salidas 1-17. Merece la pena prestar atención a algunos detalles:

En un momento dado (línea 38 del programa) tratamos de imprimir el valor de persona1.coche. Ese atributo, si prestas atención a la definición de la clase, es de tipo Coche, es decir, es un objeto en sí mismo. Por eso la respuesta rara que obtenemos en la impresión (línea 11), que en verdad es algo así como una referencia a la ubicación del objeto. Podemos tratar de profundizar en ese objeto si deseamos conocer sus atributos. Es precisamente lo que hacemos en las líneas 39-40, obteniendo la respuesta 12-13 en la salida. Presta mucha atención a la doble notación punto para preguntar por el atributo de un atributo.

Entre las líneas 42-45 preguntamos por los atributos de persona2, a la que sólo hemos facilitado su nombre. Sin embargo, Java ya ha hecho algo por nosotros.

Cada vez que se construye un nuevo objeto se invoca a un método especial que tienen todas las clases que se denomina el constructor que presentaremos formalmente en otro artículo. Entre sus funciones se encuentra la de inicializar todos los atributos del objeto. El constructor, cuando está definido explícitamente, suele incorporar en forma de argumentos valores con los que inicializar los miembros. La cuestión es que, si no hay una inicialización explícita en ese constructor, Java se ocupará de suministrar valores iniciales por su cuenta. Ese valor dependerá del tipo de variable. Por ejemplo, si es numérico le asignará el valor cero; si es un booleano, false, si es de tipo char, el carácter nulo (línea 14 de la salida, devuelta en blanco, en respuesta a la línea 42 del código) y si es un objeto (categoría entre la que se encuentran las cadenas de caracteres también), le asignará el valor null (línea 17 de la salida, en respuesta a la línea 45 del código), que es un modo que tiene Java de decirnos que es un objeto inexistente o indefinido.

A partir de la línea 47 comenzamos a probar los métodos de los objetos.

Arrancamos coche1, lo que ocasiona, si revisas el código de la clase, que la variable arrancado se establezca en true, hecho que comprobamos por medio de la línea 48, obteniendo la salida 18.

En las líneas siguientes jugamos a acelerar y a frenar el coche. Observa las salidas 19-24, en las que, después de acelerar gradualmente (incrementando en uno la velocidad) frenamos para volver a dejar el coche con velocidad cero.

Detenemos el motor del vehículo (línea 61) y hacemos sonar su claxon (línea 63, salida 26).

En las líneas de código 27-30 pedimos a persona1 y persona2 que se presenten y nos digan su nombre y edad. Observa que el método obtenerEdad() devuelve un valor numérico, al contrario de los restantes, que no retornan nada (void), de modo que para poder saber de qué valor se trata, obtenerEdad() ha de formar parte de una expresión imprimible (líneas 67 y 69).

Yo estoy cansado de tanto escribir y Marta y Raimundo de que haga el tonto con ellos. De modo que todo el mundo a dormir (líneas 70-71, salidas 31-32).

Javier Montero Gabarró


Java: Un programa para probar las clases


El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)


El Club del Autodidacta


Índice completo de artículos sobre Java.

LaTeX – Capítulo 18: Las clases por defecto y sus opciones

Hoy vamos a hablar con algo más de detalle de la primera línea de todo fichero LaTeX, la especificación de la clase de documento:

\documentclass{article}

La clase article, indicada como parámetro entre llaves, no es más que una plantilla de estilo con la que será elaborado el documento. Tradicionalmente, se dice que LaTeX ofrece cuatro clases por defecto:

article: artículos, pequeños informes y, por lo general cualquier tipo de documento no demasiado voluminoso.
book: libros
report: informes más complejos que pueden estar organizados en capítulos
letter: cartas

Tu propia distribución, sin duda, incorpora otras más, además de estas. Escanea la carpeta donde tienes instalado LaTeX y busca los ficheros con extensión .cls, propia de las clases.

En MikTeX, una de las distribuciones que uso, se encuentran en la carpeta C:\Program Files\MiKTeX 2.9\tex\latex\base. Allí, además de las clases indicadas, verás otras como slide, para presentaciones, proc, para procedimientos, o minimal, que como su nombre sugiere, se emplea para pequeños borradores.

Y no decir la infinidad de clases de terceros especializadas en casi cualquier tipo de formato y al gusto del consumidor. Por supuesto, además, tú mismo puedes diseñar clases a tu medida si aprendes a hacerlo.

Cada clase impone un estilo y la mayor parte de nuestro trabajo se limitará simplemente a escribir el texto. LaTeX se ocupará, después, del trabajo de diseño en función de los requerimientos de la clase. Pero, aún así, cada clase ofrece ciertos parámetros que se dejan a la elección del usuario. Podemos, por ejemplo, decidir que el documento se generará con una fuente de 11pt en vez de 10pt, que es el valor por defecto, o indicar que adoptará un formato a dos caras, es decir diferenciando los márgenes en las páginas pares e impares, como sucede, habitualmente, en cualquier libro.

Es decir, la clase nos ofrece ciertas opciones de parametrización. Existe un ajuste más fino aún que realizaremos utilizando paquetes que permiten extender la funcionalidad de las clases, pero eso es otra historia y hablaremos de ella en el momento adecuado.

Veamos las diferentes opciones que nos ofrece cada clase.

Abre un fichero de clase en el editor de texto, que vamos a examinar su contenido. Toma, por ejemplo, book.cls, clase adecuada para la escritura de libros.

Busca las líneas que comienzan con el comando \Declareoption. Por ejemplo, hay un bloque dedicado al tamaño del papel:

\DeclareOption{a4paper}
   {\setlength\paperheight {297mm}%
    \setlength\paperwidth  {210mm}}
\DeclareOption{a5paper}
   {\setlength\paperheight {210mm}%
    \setlength\paperwidth  {148mm}}
\DeclareOption{b5paper}
   {\setlength\paperheight {250mm}%
    \setlength\paperwidth  {176mm}}
\DeclareOption{letterpaper}
   {\setlength\paperheight {11in}%
    \setlength\paperwidth  {8.5in}}
\DeclareOption{legalpaper}
   {\setlength\paperheight {14in}%
    \setlength\paperwidth  {8.5in}}
\DeclareOption{executivepaper}
   {\setlength\paperheight {10.5in}%
    \setlength\paperwidth  {7.25in}}

Esto nos indica que la clase admite, como opciones: a4paper, a5paper, b5paper, letterpaper, legalpaper y executivepaper, indicando en cada una las dimensiones correspondientes.

Estas otras líneas nos muestran que podemos elegir entre escritura a una columna o dos:

\DeclareOption{onecolumn}{\@twocolumnfalse}
\fi
\DeclareOption{twocolumn}{\@twocolumntrue}

Existe una línea que resume las opciones por defecto que ofrece la clase en caso de que no se especifiquen otras:

\ExecuteOptions{letterpaper,10pt,twoside,onecolumn,final,openright}

Es decir, la clase book imprime en tamaño letter, con una fuente de 10pt, impresión a dos caras, una columna, formato final (no borrador) y exigiendo que los capítulos empiecen sólo en páginas impares.

Esta misma línea, en la clase article:

\ExecuteOptions{letterpaper,10pt,oneside,onecolumn,final}

Vemos, como diferencia, que los artículos se diseñan para escritura a una sola cara. No hay mención al comienzo de los capítulos (openright, openany), puesto que esta clase no los incluye.

En la clase report aparece el siguiente comando:

\ExecuteOptions{letterpaper,10pt,oneside,onecolumn,final,openany}

Compáralo con el de la clase book y observa su similitud. La diferencia está en openany, que hace que los capítulos puedan comenzar tanto en páginas pares como impares.

Una pequeña observación: aunque por defecto veas un tamaño de papel letter, probablemente en tu distribución lo tengas en A4 por defecto. Esto es así porque está configurado como opción en la propia distribución. Por ejemplo, en MikTex:

¿Cómo especificamos parámetros diferentes a los que son por defecto? Los indicamos junto al comando de declaración de clase entre corchetes:

\documentclass[11pt, oneside]{book}

Este comando indicaría que empleamos la clase book, pero con la opción de fuente de 11pt y formato de una cara. Observa que los parámetros obligatorios en un comando se escriben entre llaves, mientras que los opcionales van entre corchetes.

Voy a resumirte las diferentes opciones por categorías. Ten en cuenta que no todas ellas estarán disponibles en todas las clases.

Tamaño de fuente: 10pt, 11pt y 12pt.
Tamaño de papel: a4paper, a5paper, b5paper, letterpaper, legalpaper y executivepaper.
Orientación: landscape(apaisado, si no se indica es vertical directamente).
Formato de hoja: oneside (una cara), twoside(dos caras).
Portada: titlepage, notitlepage (con portada o sin ella).
Número de columnas: onecolumn, twocolumn
Inicio de capítulos: openright (páginas impares), openany (en cualquiera).
Edición: final y draft (para borradores).

También tienes opciones para la escritura de ecuaciones (la gran especialidad de LaTeX y por la que me decidí a estudiarlo: para poder escribir con elegancia fórmulas en artículos de física y matemáticas).

Alineación de ecuaciones: fleqn, para que queden alineadas a la izquierda en vez de centradas.
Numeración de ecuaciones: leqno, para que el número de ecuación quede alineado a la izquierda y no a la derecha.

No tienes que memorizar esto. Llegado el momento, cuando necesites utilizarlo, lo aprenderás sin esfuerzo. Todo se retiene mejor cuando hay conexión con el lado práctico.

Javier Montero Gabarró


http://elclubdelautodidacta.es/wp/2012/01/latex-capitulo-18-las-clases-por-defecto-y-sus-opciones/


El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)


El Club del Autodidacta