lunes, 18 de agosto de 2008

Python como primer lenguaje de programación

Eddy [delvalle@otepr.co.cu]

Introducing Python

Python es un lenguaje interpretado de tipado dinámico multiplataforma y multiparadigma. Lo que traducido al español indica que no se compila nunca al lenguaje nativo de la computadora, es ejecutado por otro programa llamado intérprete que se encarga de hacer todo lo que le indica el programa que hemos escrito. Gracias a esta característica Python es multiplataforma, porque cuenta con intérpretes que se pueden descargar libremente para Windows, MacOS y Linux siempre lo trae instalado, ya que este lenguaje es crucial para su funcionamiento.


Lo de "tipado dinámico" indica que nunca es especifica el tipo de una variable de forma estática lo que se considera en algunos lenguajes un sacrilegio. Permitiendo hacer algo que no es posible en muchos lenguajes como C++, C# y Java. Precisamente esto:

a = 5
a = "cadena de caracteres"
a = ObjetoA()
a = ObjetoB()

La característica que le permite ser multiparadigma es que se puede programar tanto funcionalmente como orientado a objetos en Python. Pues se pueden definir clases de objetos y funciones por separado.

La cuestión del primer lenguaje

Siempre esta cuestión ha sido muy debatida en los últimos años dado que hace unos años atrás la respuesta a esta pregunta era Pascal, el cual se consideraba elegante, sencillo y soportaba el paradigma de programación estructural.

Pero hoy nos encontramos en una Babel de los lenguajes de programación, pero veamos las características que debe cumplir un lenguaje de programación para ser el primero en el aprendizaje.

Sintaxis:
El lenguaje debe tener cierto sentido de la economía en el uso de símbolos auxiliares y sus estructuras deben seguir unos principios sencillos que permitan generalizaciones efectivas. Muchos errores de programación de los aprendices se deben a la omisión o uso incorrecto de terminadores y delimitadores de bloque, como las llaves en C, C++ y Java, (que frecuentemente pasan inadvertidos al compilador por no provocar errores sintácticos o semánticos). Estos errores no siempre se deben a un mal diseño del algoritmo por parte del programador, sino al pobre soporte que ofrece el lenguaje de programación para una expresión concisa y clara del algoritmo.

Expresividad:
El lenguaje debe poder decir mucho con poco. Para ello, el lenguaje debe ofrecer estructuras de control flexibles y presentar una colección de tipos y estructuras de datos que permita expresar relaciones complejas entre datos con una notación sencilla (por ejemplo, dando soporte sintáctico a estructuras secuenciales como las listas).

Semántica:
Esta característica debe ser los más sencilla posible. Contribuye a ello que el lenguaje sea muy ortogonal, es decir, si una construcción o método funciona con una estructura de datos, debe funcionar de modo similar con aquellas otras que guardan alguna semejanza (si cierta función o método calcula la longitud de una cadena, por ejemplo, debería calcular también la longitud de una lista, pues ambas son secuencias).

Entorno de Desarrollo Integrado:
Programar es una actividad que, especialmente en fases tempranas del aprendizaje, se basa en el método de ensayo y error. Es deseable que el lenguaje vaya acompañado de un entorno de programación que facilite un ciclo de edición-ejecución rápido. Resulta crítico, además, que se detecten y señalen correctamente los errores de todo tipo (léxicos, sintácticos, semánticos estáticos y de ejecución): nada hay más frustrante para un novato que un programa dado por bueno por un compilador y que, ”inexplicablemente”, falla en la ejecución con un mensaje tan parco como “violación de segmento”, sin indicar siquiera en qué línea se produjo el error.

Las características citadas son, a mi entender, fundamentales. Un lenguaje que las presente menguadas o que no las presente en absoluto no es un buen candidato. Hay otras características que, aunque deseables, son secundarias. Entre ellas tenemos, por ejemplo, su presencia en el “mundo real”, aunque teniendo en cuenta que está fuertemente sometido al dominio de las modas y la mercadotecnia.

Python como primer lenguaje

A continuación se recoge brevemente como son cumplidas cada una de las características anteriormente mencionadas en este lenguaje.

La sintaxis de Python es extremadamente sencilla.
Veamos un ejemplo universal: "Hola mundo":
Un lenguaje como C obliga a incorporar la cabecera de una biblioteca estándar, de?nir una función principal que devuelve un valor nulo (obligatorio en C99) y a codi?car el salto de línea de una forma críptica (al menos para una persona que no ha visto un programa en su vida):

#include <stdio.h>
int main(void)
{
  printf("Hola mundo\n");
  return 0;
}

¡Quince componentes léxicos (sin contar la directiva del preprocesador)! La cosa no mejora mucho en C++ (¡y eso sin entrar en la polémica de que cada año, o casi, hay que escribir este programa "canónico" de una forma diferente!)

#include <iostream>
int main(void)
{
  std::cout << "Hola mundo" << std::endl;
}

Y en C#, resulta complicado hasta lo inverosímil:

using System;
public class HolaMundo
{
  public static void Main(string [] args)
  {
    System.WriteLine("Hola mundo");
  }
}

¿Cómo, demonios explicar a un novato que no ha visto un programa en su vida el signi?cado de cada uno de los términos sin solicitar un acto de fe tras otro?
Python va directo al grano:

print "Hola mundo"

Naturalmente, el programa "Hola mundo" no es determinante a la hora de escoger un lenguaje de programación, pero sí debería suscitar una seria re?exión acera de la excesiva e innecesaria complejidad a la que se somete a los principiantes a la programación.

No podemos desgranar todos los elementos que hacen de Python un lenguaje de sintaxis sencilla, pero si queremos destacar uno de ellos: los bloques de código se marcan con la indentación.
Aquí tenemos un ejemplo:

def f(x):
  return x**2 - 2*x - 2

def biseccion(a, b, epsilon):
  c = (a + b) / 2.0
  while f(c) != 0 and b - a > epsilon:
    if f(a)*f(c) > 0:
      a = c
    elif f(b)*f(c) > 0:
      b = c
    c = (a + b) / 2.0
  return c

print ’x =’, biseccion(0.5, 3.5, 1e-10)

Como se puede comprobar, no hay terminadores de sentencia (como el punto y coma de C/C++/Java/C#) ni marcas de inicio y ?n de bloque (como las llaves de esos mismos lenguajes). La indentación como forma de marcar bloques elimina errores propios de los lenguajes citados y que son frecuentes en los principiantes y educa en una forma elegante y bella de escribir código. Algunos de estos errores suelen ser: sentencias condicionales sin acción por añadir un punto y coma incorrecto; bucles con una sola sentencia cuando el alumno cree que hay dos o mas por omisión de llaves con un sangrado inadecuado del programa; sentencias con semántica "alterada" por usar una coma cuando corresponde un punto y coma o por omitir un punto y coma al declarar un registro antes de una función, etc.

Python es un lenguaje interpretado.
Los lenguajes interpretados permiten ciclos de desarrollo breves (edición y ejecución), que animan a los iniciados a experimentar. Python dispone de un entorno de ejecución que ayuda a detectar los errores (incluyendo aquellos que sólo se mani?estan en tiempo de ejecución) señalándolos con mensajes muy informativos.

Ofrece, además, un entorno interactivo con el que es posible efectuar pequeñas pruebas o diseñar incrementalmente las soluciones a los problemas.

La contrapartida de que se trate de un lenguaje interpretado es, obviamente, la menor velocidad de ejecución. No obstante, esta menor velocidad no resulta en absoluto importante para los programas propios de un iniciado.

Python puede considerarse pseudocódigo ejecutable.
Muchos cursos de iniciación a la programación empiezan por presentar nociones básicas con pseudo código, es decir, con un lenguaje de programación inexistente que aporta, eso sí, la flexibilidad su?ciente para expresar cómodamente algoritmos.

Al Python ser un lenguaje tipado dinámicamente. Cada dato es de un tipo determinado (a diferencia de otros lenguajes de script, como Tcl, en los que muchos tipos son, en el fondo, cadenas) y sólo se puede operar con él de formas bien de?nidas. La ventaja es que no hay que declarar variables antes de su uso.

Esto resulta de gran ayuda para el que empieza a programar: las sutiles diferencias entre declaración y de?nición, por ejemplo, se obvian en Python. Cuando se ha acostumbrado a usar variables y ha comprendido el concepto de tipo de datos, puede transitar fácilmente a C++ y entender con mayor facilidad las ventajas de la declaraciónde variables en un lenguaje compilado.

Curiosamente, quienes critican opciones como Python por no ser un lenguaje estáticamente tipado aceptan de buen grado opciones como C o C++, lenguajes en los que "todo vale" cuando se apunta a memoria. Esta característica, que resulta útil en la programación de sistemas, se presta a enorme confusión en el principiante. No es que Python evite el trabajo con punteros, al contrario, en Python toda la información se maneja vía punteros (referencias a memoria), sino que la memoria apuntada mantiene información de tipo sobre los datos almacenados, evitando problemas de acceso a ellos con tipos erróneos.

Hay una vertiente negativa en la no necesidad de declarar variables: los errores derivados de teclear incorrectamente identi?cadores de variables o de atributos de objetos. Si se comete un error al teclear el nombre de una variable o atributo en la parte izquierda de una asignación, se crea una nueva variable. El mismo problema, cuando ocurre en la parte derecha, es detectado por el entorno de ejecución, así que no resulta tan grave.

Python facilita la detección y gestión de errores mediante excepciones.
Las excepciones forman parte ya de los lenguajes de programación modernos (Java las incorporó desde el principio y C++ lo ha hecho más recientemente) y eliminan la excesiva complejidad de la detección y tratamiento de errores con lenguajes de programación que, como C, fuerzan a detectarlos con valores especiales de retorno y que no ofrecen un modelo claro de interrupción de rutinas para localizar su tratamiento en un solo punto.

Python ofrece un rico conjunto de estructuras de datos ?exibles.
El tipo lista de Python (un vector dinámico heterogéneo) permite introducir con naturalidad el concepto de secuencia y presentar los algoritmos básicos de manejo de secuencias. Que la indexación empiece siempre en 0 ayuda a dar el salto a C, C++, C# o Java. El entorno de ejecución proporciona comprobación de validez de los índices, eliminando así una de las principales fuentes de problemas de C y C++. El hecho de que las listas sean redimensionables elimina al programador la necesidad de tomar decisiones acerca de la longitud máxima de las colecciones demasiado pronto. Es el camino que ha adoptado últimamente C++ con la STL (aunque, ¿alguien se atreve a presentar la STL en las primeras semanas de formación de un programador, con todas sus sutilezas y esa sintaxis endemoniada?).

Python es un lenguaje muy ortogonal.
Una vez se ha aprendido a manejar listas, por ejemplo, se sabe manejar cadenas, ya que ambos tipos son secuenciales y presentan conjuntos de operadores con igual nombre y semántica. Además de listas y cadenas, Python ofrece tuplas (listas inmutables) y diccionarios (vectores asociativos).

Python simplifica la gestión de memoria.
El modelo de memoria de Python es sencillo: todo valor reside en el "heap" y toda variable contiene una referencia a su valor. A ello se suma un sistema de recogida automática de basura (garbage collection) que evita los punteros colgantes (dangling pointers), las fugas de memoria, las violaciones de segmento, etc. Estos errores de ejecución, habituales en lenguajes como C o C++, son difíciles de detectar y convierten el desarrollo de programas en una actividad más frustrante de lo que es razonable, especialmente para el principiante.

Python ofrece una amplísima colección de módulos (bibliotecas).
Hay módulos para cualquier actividad imaginable: escritura de CGI, gestión de correo electrónico, desarrollo de interfaces grá?cas de usuario, análisis de documentos HTML o XML, acceso a bases de datos, trabajo con expresiones regulares, etc.

No es que haya que conocer todos estos módulos (no hay tiempo); pero sí es posible conocer que existen y su aplicación por si son necesarios en un futuro.
Acostumbrarse a consultar la documentación de las bibliotecas disponibles desde bien temprano ayuda a hacer de ellos programadores e?cientes.

Una ventaja adicional de Python es, pues, que hace posible hacer programas sobre temas "modernos": CGI, análisis de texto con expresiones regulares, interfaces gráa?cos de usuario, etc.

El mecanismo de paso de parámetros es único.
Los parámetros se pasan a funciones y métodos por referencia a objeto. En la práctica, se comporta de forma similar al paso de parámetros de Java o C#: el paso de objetos básicos (de tipo escalar) se realiza con efectos similares al paso por valor y el de objetos más elaborados (vectores, diccionarios, instancias de clase, etc.) por referencia.

def parametros(a, lista):
  a += 1
  lista.append(10)
x = 1
l = [1,2,3]
parametros(x, l)
print "x no se ha modificado:", x
print "pero a l se le ha annadido el elemento de valor 10:", l

Si bien el paso de parámetros de C es más ?exible (incluye una forma de paso de parámetros por referencia basada en el paso por valor de un puntero), el comportamiento por defecto con respecto al paso de variables de tipo báasico y vectorial es análogo al de Python, haciendo sencilla la migración posterior a este lenguaje y a C++.

Python es orientado a objetos.
A diferencia de Java y C#, Python permite una programación puramente procedular. La orientación a objetos, aunque perfectamente soportada, es opcional (a menos, naturalmente, que se recurra a ciertos módulos en los que se de?nen clases). El soporte a la programación orientada a objetos es similar al de lenguajes como Smalltalk: la resolución de los nombres de método y atributos es dinámica. Ello elimina la necesidad de complicadas jerarquías de herencia (aunque Python soporta la herencia múltiple), clases virtuales e interfaces.

Cuestiones como el diseño de contenedores genéricos está también resuelta, pues el sistema de tipos dinámico ofrece la ?exibilidad su?ciente.

class Pila:
  def __init__(self, n): # Metodo constructor.
    self.index = -1
    self.buffer = [None] * n

  def push(self, value): # Apila un elemento.
    if self.index >= len(self.buffer):
      raise "Error: Pila llena."
    self.index += 1
    self.buffer[self.index] = value

  def top(self): # Consulta la cima de la pila.
    if self.index < 0:
      raise "Error: Pila vac´ia."
    return self.buffer[self.index]

  def pop(self): # Extrae la cima de la pila.
    if self.index < 0:
      raise "Error: Pila vac´ia."
    self.index -= 1
    return self.buffer[self.index+1]

p = Pila(5)
p.push(3)
p.push(2)
print p.top()
print p.pop()
print p.pop()

Python fortalece y fundamenta la escritura de software libre:
Pues que como los programas nunca son compilados, se ejecutan desde el fichero de texto que contiene su código, este siempre es entregado al usuario del programa, permitiéndole analizarlo y modificarlo así le convenga.

exit() #Cerrando.

Espero que estos sean motivos suficientes para empezar a aprender a programar y hacer lo usando Python, pues este presenta todas las características básicas para ser un buen lenguaje para adentrarse en el mundo de las instrucciones.



Artículos relacionados


No hay comentarios: