viernes, 23 de octubre de 2015

SEMAFORO EN PYTHON

OBJETO SEMAPHORE EN PYTHON



Uno de los mecanismos más antiguos de sincronización de hilos son los semáforos (Semaphore). Un semáforo permite acceder a un determinado recurso a un número máximo de hilos simultáneamente. Si hay más hilos que el máximo permitido, los pone en espera y los va dejando pasar según van terminando los que están activos. 



Un semáforo actúa como un contador con un valor inicial. 

Cada vez que un hilo llama a Semaphore.acquire(), el contador se decrementa en 1 y se deja pasar al hilo. En el momento que el contador se hace cero, NO se deja pasar al siguiente hilo que llame a acquire(), sino que lo deja bloqueado. 

Cada vez que se llama a Semaphore.release(), el contador se incrementa en 1. Si se hace igual a cero, libera al siguiente hilo en la cola de espera.

Los semáforos son parecidos a los candados (locks), pero en vez de tomar el valor 1 y 0, toman n valores que nos indicará la cantidad de hilos que puede tomar el recurso concurrentemente.



Por lo tanto, las llamadas que podremos realizar son:

Semaphore ([value])

El argumento opcional proporciona el valor inicial del contador interno. El valor predeterminado es 1.

acquire ([blocking])

Adquirir un semáforo.

Si se invoca sin argumentos: si el contador interno es superior a cero a la entrada, lo decrementa en una unidad y retorna de inmediato. Si es cero a la entrada, bloquear la ejecución del hilo, esperando a que otro llame a release() para hacerlo mayor de cero. Se gestionan de manera adecuada los interbloqueos, por lo que si hay varias llamadas a acquire() bloqueadas a la espera, release() despertará exactamente a una de ellas. La implementación puede seleccionar una al azar, por lo que no se debe confiar en un orden de respuesta observado. No hay valor de retorno en este caso.

Si se invoca con el argumento blocking a verdadero, hacer lo mismo que si se llama sin argumentos y devolver verdadero.

Si se invoca con blocking a falso, no bloquear. Si una llamada sin argumentos bloqueara, devolver falso de inmediato. En caso contrario, hacer lo mismo que si se llama sin argumentos y devolver verdadero.

release ()

Liberar un semáforo, incrementando su contador interno en una unidad. Si era cero a la entrada y otro hilo está esperando a que sea mayor que cero, despertar a dicho hilo.

Los semáforos sirven para permitir el acceso a un recurso que admite un número máximo de hilos simultáneos. Por ejemplo, si cada hilo abre su conexión a base de datos y sólo queremos un máximo de cinco conexiones abiertas simultáneamente, un semáforo puede ser una opción.

Para ver su funcionamiento basta observar el siguiente ejemplo sencillo. En anteriores entradas del blog podemos observar todo lo relativo al módulo Threading. Por otro lado, se debe crear el semáforo indicando el valor inicial del contador (número máximo de hilos que pueden estar activos simultáneamente) :



import threading

from time import sleep

n_sem = 1

semaforo = threading.Semaphore(n_sem)



class Hilo(threading.Thread):

def __init__(self, id):

threading.Thread.__init__(self)

self.id = id



def run(self):

semaforo.acquire()

print "Hilo %s entra."%(self.id)

sleep(3)

semaforo.release()



hilos = [Hilo(1), Hilo(2), Hilo(3)]



for h in hilos:

h.start()



Finalmente, Python también nos facilita la clase BoundedSemaphore. La diferencia entre Semaphore y BoundedSemaphore es que, cuando se libera el recurso más veces que el n inicial del semáforo en Semaphore cambia dicha cota, mientras que en BoundedSemaphore lo considera un error de ValueError.

miércoles, 2 de septiembre de 2015

Programación Con Hilos



En esta nueva entrega de multiprocesamiento en Python vamos a iniciar un recorrido a fondo por los hilos y su uso hasta que no tengan secretos para nosotros. En este primer post vamos a hacer una ligera introducción.



Los hilos permiten a nuestras aplicaciones ejecutar múltiples operaciones de forma concurrente en elmismo espacio de proceso. El módulo utilizado para ello es el módulo threading.


El objeto Thread

El modo más sencillo para usar un hilo es instanciar un objeto de la clase Thread con una función objetivo y hacer una llamada a su método start().
import threading
def worker(): “”“funcion que realiza el trabajo en el thread”“” print ‘Estoy trabajando para Genbeta Dev’ return
threads = list()
for i in range(3): t = threading.Thread(target=worker) threads.append(t) t.start()


La salida del código anterior devolverá tres impresiones de la cadena “Estoy trabajando para Genbeta Dev”.



A los threads se les puede pasar parámetros que después son usados por la función objetivo. Cualquier tipo de objeto puede ser pasado como parámetro a un thread.
import threading
def worker(count): “”“funcion que realiza el trabajo en el thread”“” print “Este es el %s trabajo que hago hoy para Genbeta Dev” % count return
threads = list()
for i in range(3): t = threading.Thread(target=worker, args=(i,)) threads.append(t) t.start()


La salida del anterior ejemplo sería como la que sigue:
Este es el 0 trabajo que hago hoy para Genbeta Dev
Este es el 1 trabajo que hago hoy para Genbeta Dev
Este es el 2 trabajo que hago hoy para Genbeta Dev



Saber en que Thread nos encontramos

Se pueden usar argumentos para nombrar los threads que creamos aunque no es necesario. Cada instancia de la clase Thread tiene un nombre asigndo por defecto.

Nombrar los threads puede ser útil por ejemplo, a la hora de clarificar nuestro código.
import threading
import time
def worker(): print threading.currentThread().getName(), ‘Lanzado’ time.sleep(2) print threading.currentThread().getName(), ‘Deteniendo’
def servicio(): print threading.currentThread().getName(), ‘Lanzado’ print threading.currentThread().getName(), ‘Deteniendo’
t = threading.Thread(target=servicio, name=‘Servicio’)
w = threading.Thread(target=worker, name=‘Worker’)
z = threading.Thread(target=worker)
w.start()
z.start()
t.start()


La salida del código anterior sería:
Worker Lanzado
Thread-1 Lanzado
Servicio Lanzado
Worker Deteniendo
Thread-1 Deteniendo
Servicio Deteniendo



Usando el módulo logging

Si vamos a depurar o logear algo relacionado con los threads lo mejor es que utilicemos el módulologging para ello.
import threading
import logging
import time
logging.basicConfig( level=logging.DEBUG, format=’[%(levelname)s] – %(threadName)-10s : %(message)s’)
def worker(): logging.debug(‘Lanzado’) time.sleep(2) logging.debug(‘Deteniendo’)
w = threading.Thread(target=worker, name=‘Worker’)
w.start()


El módulo logging soporta la inclusión del nombre del hilo de forma nativa, la salida de uno de los mensajes anteriores sería parecido a esto:
[DEBUG] – Worker : Lanzado



Daemon Threads

En los ejemplos anteriores, la aplicación espera antes de acabar a que todos sus threads se hayan completado. Algunas veces querremos lanzar un thread como un daemon que se ejecuta sin bloquear el hilo principal de la aplicación permitiéndole salir en cualquier momento.

Este comportamiento es útil para servicios en los que puede que detener un hilo no sea una tarea trivial o en la que permitir que un hilo muera en mitad de un proceso no constituya una corrupción de datos. Por ejemplo, un proceso puede iniciar un hilo que haga algún tipo de ping heartbeat para monitorizar un servicio.

Para levantar un thread como daemon solo tenemos que invocar a su método setDaemon()pasándole el argumento True.
import threading
import logging
import time
logging.basicConfig( level=logging.DEBUG, format=’[%(levelname)s] – %(threadName)-10s : %(message)s’)
def daemon(): logging.debug(‘Lanzado’) time.sleep(2) logging.debug(‘Deteniendo’)
d = threading.Thread(target=daemon, name=‘Daemon’)
d.setDaemon(True)
d.start()


Si ejecutáramos el ejemplo anterior, no recibiríamos el mensaje de salida del thread puesto que la aplicación saldría sin esperarlo. Cuando el proceso termina todos los hilos son eliminados. Para esperar a que un thread daemon termine, debemos invocar explícitamente al método join().



Para saber si un thread esta vivo, podemos utilizar el método isAlive() en él, que devolverá Trueo False según su estado.
Conclusión

Hoy hemos un hecho un primer contacto con el módulo threading de Python y hemos aprendido a usar el objeto logging para usar mensajes de depurado con nuestros hilos. En el siguiente artículo trataremos temas como la enumeración de hilos, la herencia directa del objeto Thread y los threadscon temporizador.

referencias

www.genbetadev.com/python/multiprocesamiento-en-python-threads-a-f...
blog.buguroo.com/concurrencia-real-en-python

Programacion Orientada a Objetos python


Introducción a la programación orientada a objetos

Este artículo es una introducción a la programación orientada a objetos (POO, o OOP por sus siglas en inglés), uno de los paradigmas de programación estructurada más importante hoy en día.

El artículo usa el lenguaje Python para los distintos ejemplos, y explica la implementación de la POO en ese lenguaje, aunque aborda conceptos generales que son fácilmente trasladables a otros lenguajes.

Los fragmentos de código se señalan usando un estilo de texto diferente (ancho fijo) y, cuando se utiliza el intérprete de python, se prefija cada línea con los símbolos ‘>>>’.

Esta introducción presupone conocimientos básicos de programación y del lenguaje python.

Formas de pensar: paradigmas de programación

Uno de los elementos básicos a la hora de realizar un programa es la modelización del problema que pretende resolver. Es preciso localizar las variables y los aspectos relevantes, así como comprender los pasos necesarios para obtener el resultado a partir de los datos iniciales, etc. Es decir, abstraer el problema, reduciendo sus detalles de forma que podamos trabajar con pocos elementos cada vez.

La algoritmia plantea la forma óptima de resolver problemas concretos, tales como la ordenación de una lista de elementos, la búsqueda de un elemento en un conjunto, la manipulación de conjuntos de datos, etc. Sin embargo, no proporcionan un marco general, un enfoque, que nos permita plantear y formular las soluciones a un problema de forma coherente.

Los paradigmas de programación llenan ese hueco, proporcionando guías tanto sobre cómo realizar la abstracción de los datos como sobre el control de la ejecución. Es decir, los paradigmas de programación son herramientas conceptuales para analizar, representar y abordar los problemas, presentando sistematizaciones alternativas o complementarias para pasar del espacio de los problemas al de las implementaciones de una solución.

Es muy recomendable y productivo comprender el enfoque de distintos paradigmas, puesto que presentan estrategias alternativas, incrementando nuestras herramientas disponibles y haciéndono reflexionar sobre muchas de las tareas que realizamos al crear un programa. Además, a menudo ocurre que unos problemas se formulan de forma muy clara si se los analiza según una perspectiva determinada, mientras que producen una gran complejidad vistos de otra manera.
Algunos paradigmas habituales

Algunas de las formas de pensar los problemas que ha llegado a sistematizarse como paradigmas de programación son:
La programación modular: Los programas se forman por partes separadas llamadas módulos. Estos funcionan de forma independiente entre sí, o se relacionan a través de interfaces bien definidas.
La programación procedural: Un programa se compone de procedimientos (subrutinas, métodos o funciones) que son fragmentos de código que pueden llamarse desde cualquier punto de la ejecución de un programa, incluídos otros procedimientos o él mismo. (ej. ALGOL)
La programación estructurada: Se puede expresar cualquier programa utilizando únicamente tres estructuras de control: secuencial, condicional e iterativa. Los programas se componen de partes menores con un único punto de entrada, y se trata de aislarlos para evitar la complejidad que introducen los efectos colaterales. (ej. Pascal, C, Ada)
La programación imperativa: Un programa se puede definir en términos de estado, y de instrucciones secuenciales que modifican dicho estado. (ej. C, BASIC)
La programación declarativa: Es posible expresar un programa a través de condiciones, proposiciones o restricciones, a partir de los que se obtiene la solución mediante reglas internas de control. (ej. PROLOG)
La programación funcional: Se puede expresar un programa como una secuencia de aplicación de funciones. Elude el concepto de estado del cómputo y no precisa de las estructuras de control de la programación estructurada. (ej. LISP, Haskell)
La programación orientada a objetos: Los programas se definen en términos de “clases de objetos” que se comunican entre sí mediante el envío de mensajes. Es una evolución de los paradigmas de la programación procedural, estructurada y modular, y se implementa en lenguajes como Java, Smalltalk, Python o C++.
Programación multiparadigma

Los paradigmas de programación son idealizaciones, y, como tales, no siempre se presentan de forma totalmente ‘pura’, ni siempre resultan incompatibles entre sí. Cuando se entremezclan diversos paradigmas se produce lo que se conoce como programación multiparadigma.

El uso de distintos modelos, según se adapten mejor a las diversas partes de un problema o a nuestra forma de pensamiento, resulta también más natural y permite expresar de forma más clara y concisa nuestras ideas.

Algunos lenguajes, como Haskell o Prolog están diseñados para encajar perfectamente en la visión de un paradigma particular, mientras que otros, como python, se adaptan especialmente bien a la programación multiparadigma y dan gran libertad a la hora de resolver un problema, al no imponen un mismo patrón para todos los casos.
Tipos de datos

Una forma de almacenar y representar una fecha en un programa podría ser la siguiente:

d = 14 m = "Noviembre" a = 2006 def dime_fecha(dia, mes, anho): return "%i de %s de %i del calendario gregoriano" % (dia, mes, anho) print dime_fecha(d, m, a)




para obtener la siguiente salida:

"14 de Noviembre de 2006"

En este ejemplo, para representar y manipular lo que conceptualmente entendemos como una fecha, se utilizan las variables d, m y a como almacenes de datos, y un procedimiento o función, de nombre dime_fecha, para realizar la representación de la fecha almacenada.

Las variables permiten almacenar tipos de datos concretos como los enteros (d y a) o las cadenas de texto (m), y la función realiza su trabajo devolviendo otro tipo concreto, una cadena de texto.

Uno de los problemas de este enfoque es que no refleja demasiado bien el concepto fecha que usamos como modelo mental al implementarlo como un conjunto de tres variables no relacionadas entre sí (d, m y a). Es decir, las tres variables tienen una unidad conceptual en nuestra mente, que no se refleja en la forma de expresar el problema. De la misma manera, la función dime_fechadesconoce igualmente la relación entre sus parámetros, que podría ser totalmente arbitraria.

Esta situación, que puede parecer una cuestión de ‘estilo’, implica un riesgo de problemas de sincronización entre variables ‘relacionadas’, dispersión en distintas partes del código de manipulaciones que son relevantes al conjunto, pérdida del valor semántico de cada variable que puede dar lugar a errores al transformar el código…

Un ejemplo de desconexión semántica entre la implementación y el concepto es que d puede ser cualquier valor entero, mientras que un día tiene un valor situado entre 1 y 31, m es una cadena de texto dentro de un número limitado de opciones, o a no puede tomar valores negativos. Por supuesto que esto se podría solucionar con código que hiciese comprobaciones adicionales, pero en este caso queremos resaltar cómo un programa es un modelo aproximado a un problema y cómo sería preferible que la implementación pudiese representar de forma más ajustada el comportamiento del modelo elegido.

Una posible solución sería disponer de un tipo de datos que represente de forma más adecuada el concepto de fecha y que nos permita manipular fechas de la misma manera que manipulamos números enteros, números reales o cadenas de texto, independientemente de la implementación interna que los sustente.
Clases y objetos

Al enunciar algunos tipos de paradigmas hemos visto que la programación orientada a objetos define los programas en términos de “clases de objetos” que se comunican entre sí mediante el envío de mensajes. En este apartado aclararemos qué se entiende en ese contexto por clases y objetos.

Las clases surgen de la generalización de los tipos de datos y permiten una representación más directa de los conceptos necesarios para la modelización de un problema permitiendo definir nuevos tipos al usuario.

Las clases permiten agrupar en un nuevo tipo los datos y las funcionalidades asociadas a dichos datos, favoreciendo la separación entre los detalles de la implementación de las propiedades esenciales para su uso. A esta cualidad, de no mostrar más que la información relevante, ocultando el estado y los métodos internos de la clase, es conocida como “encapsulación”, y es un principio heredado de la programación modular.

Un aspecto importante en el uso de clases es que no se manipulan directamente (salvo en lo que se conoce como metaprogramación), sino que sirven para la definición nuevos tipos. Una clase define propiedades y comportamiento que se muestran en los entes llamadosobjetos (o instancias de una clase). La clase actúa como molde de un conjunto de objetos, de los que se dice que pertenecen a la clase.

Trasladando estos conceptos a los números enteros (tipo int), se puede decir que las variables que almacenan números enteros son objetos o instancias de la clase int o que pertenecen a la clase int.

En términos más abstractos, podemos pensar en las clases como definiciones y en los objetos como expresiones concretas de dichas definiciones.
Fisonomía de una clase

En python, el esquema para la definición de una clase es el siguiente:

class NombreClase: <instrucción_1> ... <instrucción_n>




en donde class es una palabra reservada que indica la declaración de una clase, NombreClase una etiqueta que da nombre a la clase y, los dos puntos, que señalan el inicio del bloque de instrucciones de la clase.

El cuerpo de instrucciones de la clase puede contener tanto asignaciones de datos como definiciones de funciones. Este bloque de instrucciones se encuentra en el nuevo espacio de nombres con el nombre de la clase, que se genera, a su vez, con la creación de cada objeto. En ambos casos, en el espacio de nombres de la clase y del objeto, es posible acceder a los elementos que lo integran usando el operador punto, como en el caso de los espacios de nombres de un módulo (e.j. math.pi, objeto.dato, objeto.funcion()).

Si la primera instrucción del cuerpo de la clase es una cadena de texto, ésta se usa como cadena de documentación de la clase.

Nuestro ejemplo podría reescribirse en términos de una clase así:

class Fecha: "Ejemplo de clase para representar fechas" dia = 14 mes = "Noviembre" anho = 2006 def dime_fecha(self): return "%i de %s de %i" % (Fecha.dia, Fecha.mes, Fecha.anho) mi_fecha = Fecha() print mi_fecha.dia, mi_fecha.mes, mi_fecha.anho print mi_fecha.dime_fecha()




En el fragmento de código anterior definimos la clase Fecha y ella asignamos valores a las etiquetas dia, mes y anho (atributos de la clase), y definimos una función (un método de la clase), dime_fecha.

Fuera de la definición de la clase creamos (instanciamos) un objeto perteneciente a la clase Fecha. Esta instanciación se realiza utilizando la notación de llamada a función, y podemos entenderla como una llamada a una función que devuelve un objeto de la clase Fecha. El objeto obtenido es asignado a la etiqueta mi_fecha.

En la siguientes instrucciones mostramos por pantalla los valores de las propiedades dia, mes y anho y el resultado de la llamada al métododime_fecha, usando el operador punto para acceder a las propiedades y métodos del objeto mi_fecha, ya que, como hemos mencionado antes, forman parte del espacio de nombres del objeto.

La llamada al método dime_fecha no incluye ningún parámetro, pero podemos comprobar que, de forma contradictoria, la declaración del método indica uno, self. Este parámetro es añadido automáticamente por el intérprete en las llamadas a los métodos de una clase, y contiene una referencia al objeto que recibe la señal (el que recibe una llamada a un método). self permite acceder a las propiedades y métodos de un objeto concreto y aclararemos su significado y uso más adelante. Por ahora nos basta saber que es necesario incluir selfcomo primer parámetro de los métodos definidos en una clase y que no es preciso incluir el parámetro implícito self al realizar llamadas a un método a través del objeto al que pertenece.

En realidad, en el ejemplo anterior, la llamada mi_fecha.dime_fecha() es una forma más cómoda de escribir (azúcar sintáctico) Fecha.dime_fecha(mi_fecha), lo que explica la presencia del parámetro.
Un paseo entre objetos

Hasta el momento hemos visto cómo las clases definen los datos (o estado) y comportamiento de los objetos a través de atributos (o propiedades) y métodos.

Ahora vamos a hacer un recorrido, utilizando una sesión interactiva del intérprete y las capacidades de introspección de python, para explicar el uso y el comportamiento de los objetos.

Veremos algunas características de los objetos:
Identidad. Los objetos se diferencian entre sí, de forma que dos objetos, creados a partir de la misma clase y con los mismos parámetros de inicialización, son entes distintos.
Definen su comportamiento (y operar sobre sus datos) a través de métodos, equivalentes a funciones.
Definen o reflejan su estado (datos) a través de propiedades o atributos, que pueden ser tipos concretos u otros objetos.

Pasamos a ver una sesión interactiva del intérprete:


>>> mi_fecha = Fecha()
>>> mi_fecha_2 = Fecha()
>>> mi_fecha is mi_fecha_2
False
>>> print mi_fecha
<__main __.Fecha instance at 0x00B184B8>
>>> print mi_fecha_2
<__main __.Fecha instance at 0x00B18328>


Vemos que tanto mi_fecha como mi_fecha_2 son instancias de la clase Fecha (en el módulo __main__) y cada una tiene su propio espacio de memoria independiente.


>>> print mi_fecha.dime_fecha()
14 de Noviembre de 2006
>>> print mi_fecha.dia
14
>>> print mi_fecha_2.dia
14
>>> Fecha.dia = 16
>>> print Fecha.dia
16
>>> print mi_fecha.dia
16
>>> print mi_fecha_2.dia
16
>>> mi_fecha.dia = 30
>>> print Fecha.dia
16
>>> print mi_fecha.dia
30
>>> print mi_fecha_2.dia
16


Este último experimento observamos cómo, pese a que mi_fecha y mi_fecha_2 son dos instancias distintas de la clase Fecha, ambas hacen referencia a través de su atributo dia al mismo valor de la clase Fecha.dia. Sin embargo, cuando se produce una asignación a ese atributo (a esa etiqueta, en realidad) en uno de los objetos vemos cómo, a partir de entonces, ese objeto dispone de un valor ‘individual’ asociado al atributo.

Ese comportamiento revela la existencia de atributos (o estado) compartidos por todas las instancias de una clase y de atributos (o estado) ligados a una instancia particular. Los primeros se sitúan en el espacio de nombres de la clase, y vemos cómo se pueden hacer asignaciones en la sesión interactiva anterior, o lecturas, en el método dime_fecha del ejemplo anterior. Los segundos se sitúan en el espacio de nombres de cada objeto, y ahí es donde resulta útil el parámetro self.

Antes de proseguir, podemos escudriñar qué símbolos son accesibles y qué contienen los espacios de nombres de la clase Fecha y de los objetos mi_fecha y mi_fecha_2. Usamos la función dir para lo primero, y el atributo __dict__ para lo segundo, ya que en python los espacios de nombres se implementan como diccionarios:


>>> dir(Fecha)
['__doc__', '__module__', 'anho', 'dia', 'dime_fecha', 'mes']
>>> dir(fecha3)
['__doc__', '__module__', 'anho', 'dia', 'dime_fecha', 'mes']
>>> dir(fecha4)
['__doc__', '__module__', 'anho', 'dia', 'dime_fecha', 'mes']


En los tres podemos acceder a los mismos símbolos. Sin embargo…


>>> Fecha.__dict__
{'__module__': '__main__', 'anho': 2006, 'dime_fecha': , 'dia': 14, 'mes': 'Noviembre', '__doc__': 'Ejemplo de clase para representar fechas'}
>>> mi_fecha_2.__dict__
{}
>>> mi_fecha.__dict__
{'dia': 30}


El espacio de nombres de la clase es el que alberga los nombres de los atributos y métodos indicados en la declaración de la clase, además de los atributos especiales __doc__, que contiene la cadena de documentación y __module__, que contiene el nombre del módulo al que pertenece la clase. Esos símbolos son accesibles también para los objetos pertenecientes a la clase (tal como nos indicaba dir()).

Podemos ver también que el espacio de nombres del objeto mi_fecha_2 se encuentra vacío, mientras que el del objeto mi_fecha contiene el atributo día. Esto se debe a que anteriormente realizamos una asignación al atributo dia del objeto mi_fecha (dándole el valor 30). El espacio de nombres recoge esa versión particular del atributo, que no aparece en el otro objeto, puesto que accede al atributo de clase.

A los atributos compartidos por todos los objetos de una clase se los denomina atributos de clase, cuando se desea diferenciarlos de los atributos que pertenecen a cada instancia en particular.
Acceso individualizado a objetos: self

Ahora que hemos visto cómo usar atributos de clase para compartir datos entre todos los objetos de una misma clase, también nos interesa conocer cómo utilizar atributos comunes a una clase pero que puedan tomar valores distintos para cada uno de los objetos.

Retomamos ahora el misterioso parámetro self que vimos estaba presente como primer parámetro de todos los métodos de una clase. En su momento ya comentamos que self contiene una referencia al objeto que recibe la señal (el objeto cuyo método es llamado), por lo que podemos usar esa referencia para acceder al espacio de nombres del objeto, es decir, a sus atributos individuales.

>>> class F: ... i = 5 ... def dime_i(self): ... return F.i ... def dime_mi_i(self): ... return self.i ... >>> a = F() >>> a.dime_i() 5 >>> a.dime_mi_i() 5 >>> a.i = 6 >>> a.dime_i() 5 >>> a.dime_mi_i() 6 >>> a.i 6




En este ejemplo el método dime_i usa el atributo de clase y retorna su valor, 5, mientras que el método dime_mi_i usa una referencia al objeto y devuelve el valor 6, el asignado al atributo del objeto a. Así accedemos selectivamente al atributo de clase i o al atributo de instancia i.

Algo que puede aclarar algo más la naturaleza del parámetro self, es recordar que, cuando hacemos una llamada a un método un_metodode un objeto un_objeto perteneciente a la clase UnaClase, el intérprete traduce la expresión un_objeto.un_metodo() comoUnaClase.un_metodo(un_objeto).

El uso de self responde a la forma particular en que python implementa el soporte de objetos, aunque lenguajes como Java o C++ utilizan mecanismos similares con la palabra reservada this. En python self no es una palabra reservada y cualquier etiqueta usada como primer parámetro valdría igualmente, aunque se desaconseja totalmente el uso de otras etiquetas, por tratarse de una convención muy arraigada en el lenguaje que hace el código más legible, facilita el resaltado de sintaxis, etc.
El método de inicialización __init__

Hemos visto ya cómo definir y usar atributos de clase y de instancia. Pero en python no es necesaria la declaración de variables, por lo que cualquier atributo al que se realice una asignación en el código se convierte en un atributo de instancia:


>>> a = F()
>>> a.i = 6
>>> a.atr = 3
>>> print a.atr
3
>>> a.__dict__
{'i': 6, 'atr': 3}


Una funcionalidad muy conveniente que hemos visto en la declaración de atributos de clase es la de realizar su inicialización en el cuerpo de la clase. Para poder inicializar los atributos de una instancia existe un método especial que permite actuar sobre la inicialización del objeto. Dicho método se denomina __init__ (con dos guiones bajos al principio y al final) y admite cualquier número de parámetros, siendo el primero la referencia al objeto que es incializado (self, por convención), que nos permite realizar las asignaciones a atributos de la instancia. Este método se ejecuta siempre que se crea un nuevo objeto de la clase, tras la asignación de memoria y con los atributos de clase inicializados, y se corresponde parcialmente con el concepto de constructor de la clase existente en otros lenguajes.

Con la referencia que nos proporciona self podemos inicializar atributos de instancia, con valores predeterminados si lo deseamos, como en cualquier definición de función:

class Clase: def __init__(self, x=2): self.x = x self.a = x**2 self.b = x**3 self.c = 999 def dime_datos(self): return "Con x=%i obtenemos: a=%i, b=%i, c=%i" % (self.x, self.a, self.b, self.c) a1 = Clase(2) a1.dime_datos() a2 = Clase(3) a2.dime_datos()




Salida:


Con x=2 obtenemos: a=4, b=8, c=999
Con x=3 obtenemos: a=9, b=27, c=999

Propiedades y Atributos

Aunque en la terminología general de la programación orientada a objetos atributo y propiedad se pueden utilizar como sinómimos, en python se particulariza el uso de propiedades para un tipo especial de atributos cuyo acceso se produce a través de llamadas a funciones.

class ClaseC(object): def __init__(self): self.__b = 0 def __get_b(self): return self.__b def __set_b(self, valor): if valor > 10: self.__b = 0 else: self.__b = valor b = property(__get_b, __set_b, 'Propiedad b') c1 = ClaseC() print c1.b # b es 0 c1.b = 5 print c1.b # b es 5 c2 = ClaseC() print c2.b # b es 0 c2.b = 12 print c2.b #b es 0




En este ejemplo se define la propiedad b, cuyo comportamiento es: cuando se realiza una asignación, toma el valor entregado si es menor que 10, o 0 en caso contrario, y lo almacena en un atributo privado __b. Cuando se produce la lectura de b, devuelve el valor guardado en el atributo privado.

En Python, para poder usar propiedades en una clase es necesario hacerla derivar de la clase object de ahí que aparezca al lado del nombre de la clase ClaseC. En un apartado posterior se explicará en qué consiste la derivación de clases.

La signatura de la función property, que define una propiedad de la clase es la siguiente:
nombre_propiedad = property(get_f, set_f, del_f, doc)
donde get_f es la función llamada cuando se produce la lectura del atributo; set_f la función llamada cuando se produce una asignación al atributo; del_f la función llamada cuando se elimina el atributo, y doc es una cadena de documentación de la propiedad.

Las propiedades resultan muy útiles para realizar la validación de los valores asignados, la transformación o cálculo de valores devueltos y, además, dotan de gran flexibilidad a la hora de escribir el código, puesto que es posible empezar usando atributos y luego sustituirlo por una propiedad que realice funciones adicionales, a medida que el código lo requiera y simplemente cambiando el código de la clase, sin afectar al código cliente de la clase.
Herencia y derivación de clases

Vemos que el uso de clases hace más adecuada la representación de conceptos en nuestros programas. Además, es posible generar una clase nueva a partir de otra, de la que recibe su comportamiento y estado (métodos y atributos), adaptándolos o ampliándolos según sea necesario.

De una clase que representase el concepto de vehículo podríamos derivar otras para representar automóviles, bicicletas, barcos o aviones, donde cada uno de ellos mantiene atributos y métodos comunes (peso, color, velocidad máxima, número de pasajeros), mientras que otros son exclusivos (número de ruedas, número de hélices, número de reactores, altitud máxima de vuelo…).

En términos matemáticos podemos expresarlo diciendo que es posible establecer relaciones de pertenencia entre clases. Si tenemos una clase A y de ella derivamos una clase B, podemos decir que “B es una A“, o que “B es una especialización de A“.

En la terminología de la POO se dice que “B hereda de A“, “B es una clase derivada de A“, “A es la clase base de B“, “A es superclase de B” o “A es clase madre de B“.

Esto facilita la reutilización del código, puesto que se pueden implementar los comportamientos y datos básicos en una clase base y especializarlos en las clases derivadas.

En un programa hipotético que trabajase con formas geométricas, podríamos tener una clase base Forma y clases derivadas de ella comoTriangulo, Cuadrado, Circulo… En la clase base podríamos definir un método dibuja que representa la figura en pantalla, y un método area y otro perímetro que calculan el área y el perímetro, respectivamente.

En el lenguaje python, para expresar que una clase deriva, desciende o es heredera de otra u otras clases se añade tras el nombre, en la declaración de la clase, una tupla con los nombres de las clases base.

El siguiente ejemplo crea una ClaseA y de ella deriva una ClaseB que inicializa un atributo adicional, cambia el comportamiento de un método y hereda los atributos de la clase madre:

class ClaseA: def __init__(self, x): self.a = x self.b = 2 * x def muestra(self): print "a=%i, b=%i" % (self.a, self.b) class ClaseB(ClaseA): def __init__(self, x, y): ClaseA.__init__(self, x) self.c = 3 * (x + y) + self.b def muestra(self): print "a=%i, b=%i, c=%i" % (self.a, self.b, self.c) print "Objeto A" a = ClaseA(2) print a.__dict__ a.muestra() print "ObjetoB" b = ClaseB(2, 3) print b.__dict__ b.muestra()




Este código al ejecutarse devuelve:


Objeto A
{'a': 2, 'b': 4}
a=2, b=4
ObjetoB
{'a': 2, 'c': 19, 'b': 4}
a=2, b=4, c=19


La clase ClaseA muestra funcionalidades que ya hemos ido viendo en esta introducción (atributos de instancia a y b, método muestra). La clase ClaseB se declara como descendiente de la ClaseA, por lo que hereda sus métodos y atributos y modifica algo el comportamiento de la clase madre. Por una parte, en su método de inicialización llama al método de la clase madre con los parámetros deseados, y, posteriomente, añade un nuevo atributo de instancia que no existe en la clase madre. Por otro lado, redefine un método existente enClaseA, cambiando la implementación.

Esta última técnica, en la que un mismo nombre se asocia a comportamientos distintos se conoce como polimorfismo, y se habla de que el método se ha sobrecargado, es decir, se le asignan distintos significados en función de su contexto. El polimorfismo también alude a la posibilidad de utilizar, en un contexto en el que se espera una clase dada, cualquier clase derivada.
La clase object

Desde la versión 2.2 de python, se ha establecido una clase base llamada object de la que se aconseja derivar todas las clases. Esto permite aprovechar una serie de características sólo existentes en las “nuevas clases” (como la definición de propiedades), que se describen en la documentación de python.

En el ejemplo sobre el uso de propiedades se introdujo la herencia sin explicarla, derivando la clase de object. Ahora debería estar más clara la razón :).
Jerarquías de clases

La herencia permite establecer relaciones entre clases, y, estas relaciones de pertenencia pueden ser a varios niveles, y ramificarse en lo que se denominan jerarquías de clases.

Un ejemplo de clásico para visualizar las jerarquías de clases es el que podría servir para modelizar el conjunto de empleados de una empresa. En ella aparece una clase base Empleado, que dispone de los atributos nombre y departamento; de ella descienden las subclasesGestor (atributo adicional informes) y Trabajador (atributo adicional proyectos), y de esta última derivan las clases Comercial (atributo adicional participación) e Ingeniero (atributo original area).

Gráficamente podría representarse de la siguiente manera:



En el diagrama se puede ver en negrita los atributos que implementa cada clase, y en gris los que hereda de clases madre. El código (básico de inicialización) de las clases podría ser el siguiente:

class Empleado: def __init__(self, nombre, departamento="general"): self.nombre = nombre self.departamento = departamento class Gestor(Empleado): def __init__(self, nombre): Empleado.__init__(self, nombre) self.informes = [] class Trabajador(Empleado): def __init__(self, nombre): Empleado.__init__(self, nombre) self.proyectos = [] class Comercial(Trabajador): def __init__(self, nombre, participacion=0.1): Trabajador.__init__(self, nombre) self.departamento = "ventas" self.participacion = participacion class Ingeniero(Trabajador): def __init__(self, nombre, area="mecánica"): Trabajador.__init__(self, nombre) self.departamento = "ingeniería" self.area = area




Naturalmente, cada una de las clases tendría sus propios métodos que definirían comportamientos propios de cada clase o subclase, que no se han detallado en el ejemplo.

Una alternativa a la herencia es la composición, en el que una clase se compone de otras clases internas, y que puede ser una mejor alternativa en muchos casos.
Encapsulación y grados de privacidad

Uno de los principios que guían la POO, heredados de la programación modular, es el de encapsulación. Hemos visto cómo se puede agrupar comportamiento y datos gracias al uso de objetos, pero hasta el momento, tanto los atributos como los métodos que se definen en las clases correspondientes se convierten en métodos y atributos visibles para los usuarios de la clase (la API de la clase).

Se dice que un método o atributo es público si es accesible desde el exterior de la clase, mientras que se denomina privado en caso contrario.

Es deseable poder señalar qué métodos y atributos no deben utilizarse fuera de la clase para evitar exponer excesivamente los detalles de la implementación de una clase o un objeto.

Python utiliza para ello convenciones a la hora de nombrar métodos y atributos, de forma que se señale su carácter privado, para su exclusión del espacio de nombres, o para indicar una función especial, normalmente asociada a funcionalidades estándar del lenguaje.
_nombre

Los nombres que comienzan con un único guión bajo indican de forma débil un uso interno. Además, estos nombres no se incorporan en el espacio de nombres de un módulo al importarlo con “from … import *”.
__nombre

Los nombres que empiezan por dos guiones bajos indican su uso privado en la clase.

Por ejemplo, en la definición de clase siguiente:

class ClaseA: def __init__(self, a) self.__a = a self.x = self.__a**2 + 2 self.y = self.__a**3 + 3




el atributo __a es de uso interno de la clase y no se exporta directamente. A continuación podemos ver cómo trata los atributos ‘privados’ python:


>>> a = ClaseA(2)
>>> dir(a)
['_ClaseA__a', '__doc__', '__init__', '__module__', 'x', 'y']
>>> a.__dict__
{'x':6, 'y':11, '_ClaseA__a':2}


Todavía es posible acceder a __a, pero el nombre es transformado a '_ClaseA__a', que lo señala como un atributo de uso privado.
__nombre__

Los nombres que empiezan y acaban con dos guiones bajos indican atributos “mágicos”, de uso especial y que residen en espacios de nombres que puede manipular el usuario. Solamente deben usarse en la manera que se describe en la documentación de python y debe evitarse la creación de nuevos atributos de este tipo.

Algunos ejemplos de nombres “singulares” de este tipo son:
__init__, método de inicialización de objetos
__del__, método de destrucción de objetos
__doc__, cadena de documentación de módulos, clases…
__class__, nombre de la clase
__str__, método que devuelve una descripción de la clase como cadena de texto
__repr__, método que devuelve una representación de la clase como cadena de texto
__module__, módulo al que pertenece la clase
Se puede consultar la lista de atributos de este tipo y su descripción detallada en la documentación de python.
Resúmen final

La programación orientada a objetos enuncia la posibilidad de escribir un programa como un conjunto de clases de objetos capaces de almacenar su estado, y que interactúan entre sí a través del envío de mensajes.

Las técnicas más importantes utilizadas en la programación orientada a objetos son:
Abstracción: Los objetos pueden realizar tareas, interactuar con otros objetos, o modificar e informar sobre su estado sin necesidad de comunicar cómo se realizan dichas acciones.
Encapsulación (u ocultación de la información): los objetos impiden la modificación de su estado interno o la llamada a métodos internos por parte de otros objetos, y solamente se relacionan a través de una interfaz clara que define cómo se relacionan con otros objetos.
Polimorfismo: comportamientos distintos pueden estar asociados al mismo nombre
Herencia: los objetos se relacionan con otros estableciendo jerarquías, y es posible que unos objetos hereden las propiedades y métodos de otros objetos, extendiendo su comportamiento y/o especializándolo. Los objetos se agrupan así en clases que forman jerarquías.

Las clases definen el comportamiento y estado disponible que se concreta en los objetos.

Los objetos se caracterizan por:

Tener identidad. Se diferencian entre sí.
Definir su comportamiento a través de métodos.
Definir o reflejar su estado a través de propiedades y atributos.

referencia
https://librosweb.es/libro/python/capitulo_5/programacion_orientada_a_objetos.html
http://frontendlabs.io/1305--tutorial-basico-de-python-parte-iv-programacion-orientada-a-objetos

miércoles, 26 de agosto de 2015

Tarea 2 Leyes de Amdahl ,Gutafsons y Procesamiento Pipeline


Pipeline
En computación, se le llama pipeline a una serie de elementos de procesamiento de datos ordenados de tal modo que la salida de cada uno es la entrada del siguiente, como quien dice una cadena de montaje pero en vez de orientada a la manufactura, orientada al procesamiento de datos e instrucciones.

La arquitectura en pipeline (basada en filtros) consiste en ir transformando un flujo de datos en un proceso comprendido por varias fases secuenciales, siendo la entrada de cada una la salida de la anterior.
Esta arquitectura es muy común en el desarrollo de programas para el intérprete de comandos, ya que se pueden concatenar comandos fácilmente con tuberías (pipe).
También es una arquitectura muy natural en el paradigma de programación funcional, ya que equivale a la composición de funciones matemáticas.



Ley de Amdahl


El aumento de rendimiento que puede obtenerse al mejorar alguna parte de una computadora puede calcularse utilizando la Ley de Amdahl. 
La Ley de Amdahl establece que la mejora obtenida en el rendimiento al utilizar algún modo de ejecución más rápido está limitada por la fracción de tiempo que se pueda utilizar ese modo más rápido. 
La Ley de Amdahl define la ganancia de rendimiento o aceleración (speedup) que puede lograrse al utilizar una característica particular. 

La aceleración nos indica la rapidez con que se realizará una tarea utilizando una máquina con la mejora con respecto a la máquina original. La Ley de Amdahl nos da una forma rápida de calcular la aceleración, que depende de dos factores:

1. La fracción del tiempo de cálculo de la máquina original que pueda utilizarse para aprovechar la mejora. Por el ejemplo, si 20 segundos del tiempo de ejecución puede utilizar la mejora de un programa que toma 60 segundos en total, la fracción es 20 /60. Este valor, que se llama Fracción mejorada, es siempre menor o igual que 1.

2. La optimización lograda por el modo de ejecución mejorado; es decir, cuánto más rápido con la que se ejecutaría la tarea si solamente se utilizase el modo mejorado. Este valor es el tiempo del modo original con respecto al tiempo del modo mejorado. Si el modo mejorado toma 2 segundos para alguna porción de programa que puede usar el modo completamente mientras que el modo original tomaba 5 segundos para la misma porción de programa, la mejora es 5/2. Este valor es siempre mayor que 1 y se llama Aceleración mejorada.

El tiempo de ejecución utilizando la máquina original con el modo mejorado será el tiempo empleado utilizando la parte no mejorada de la máquina más el tiempo empleado utilizando la parte mejorada.

Ley de Gustafson


La ley de Gustafson (también conocida como ley de Gustafson-Barsis)1 es una ley en ciencia de la computación que establece que cualquier problema suficientemente grande puede ser eficientemente paralelizado. La ley de Gustafson está muy ligada a la Ley de Amdahl, que pone límite a la aceleración que se puede obtener gracias a la paralelización, dado un conjunto de datos de tamaño fijo, ofreciendo así una visión pesimista del procesamiento paralelo. Por el contrario la ley de Gustafson ofrece un nuevo punto de vista y así una visión positiva de las ventajas del procesamiento paralelo. John L. Gustafson enunció por primera vez la ley que lleva su nombre en 1988.

La ley de Gustafson aborda las limitaciones de la Ley de Amdahl, la cual no escala la disponibilidad del poder de cómputo a medida que el número de máquinas aumenta. La ley de Gustafson propone que los programadores establezcan el tamaño de los problemas para utilizar el equipamiento disponible en su solución en un tiempo práctico. Por consiguiente, si existe equipamiento más rápido disponible, mayores problemas se pondrán resolver en el mismo tiempo.

La Ley de Amdahl se basa en una carga de trabajo o tamaño de entrada prefijados. Esto implica que la parte secuencial de un programa no cambia con respecto al número de procesadores de la máquina, sin embargo, la parte paralelizable es uniformemente distribuida en el número de procesadores. El impacto de la ley de Gustafson fue el cambio de dirección de los objetivos de investigación hacia la selección o reformulación de problemas a fin de que fuera posible la solución de mayores problemas en el mismo intervalo de tiempo. En particular la ley redefine la eficiencia como una necesidad para minimizar la parte secuencial de un programa, incluso si esto incrementa la cantidad total de cálculos


Referencias
http://www.infor.uva.es/~bastida/Arquitecturas%20Avanzadas/General.pdf
https://es.wikipedia.org/wiki/Ley_de_Gustafson
http://mixteco.utm.mx/~merg/AC/2009/2.7-principios_cuantitativos.h ml


martes, 25 de agosto de 2015

Programación android con python



PROGRAMACION ANDROID CON PYTHON

Android es un sistema operativo inicialmente pensado para teléfonos móviles, al igual que iOS, Symbian y Blackberry OS. Lo que lo hace diferente es que está basado en Linux, un núcleo de sistema operativo libre, gratuito y multiplataforma.


QPython es un motor de secuencias de comandos que se ejecutan en los dispositivos Android. Permite correr proyectos y scripts python en nuestros dispositivos Android. Contiene un intérprete Python, consola, un editor, y la librería SL4A para Android. Es Python corriendo en Android!

Ofrece un kit de desarrollo que permite desarrollar fácilmente proyectos y scripts de Python en los dispositivos Android.

Características principales:
Soporta programación Python en Android incluyendo aplicaciones web, juegos y programación SL4A.
Ejecutar Scripts de Python y Proyectos en dispositivos Android.
Se puede ejecutar código Python y archivos de QRCode.
QEdit le permite crear/editar los scripts de Python y Proyectos fácilmente.
incluye muchas librerías útiles de Python.


Programacion android con Python
Primero tendremos que descargar el SDK de android en el siguiente link: http://developer.android.com/sdk/index.html


mi recomendación es crear una carpeta en nuestra unidad C: que se llame android y dentro instalar nuestro SDK,una vez instalado vamos a crear nuestro android emulado, por lo que vamos a ejecutar nuestro SDK para poder instalar las APIS necesarias y ejecutamos sdk.exe y instalaremos por ejemplo las de la 3.0


  • le damos a install packages y después aceptamos la licencia y le damos a install.
una vez instaladas las apis nos vamos a crear nuestro emulador y ejecutamos avd.exe.
Le pulamos en new para crear un nuevo emulador y escogemos la versión que nos hemos descargado antes en este caso la 3.0 y lo demás lo podemos dejar así, creo que no es necesario decir nada mas en este punto, lo demás es intuitivo, como por ejemplo escoger el tipo de dispositivo que queremos utilizar...

device: tipo de dispositivo

target:versión del dispositivo

cpu/abi: tipo de cpu(la que mas les convenga)

memori ram: ram para el dispositvo (recomendaria entre 250 y 500)

internal storage: la memoria interna del dispositivo(se puede dejar así)

sd card: memoria de la sd(recomendaría entre 1000 y 1500 MIB)

  • una vez escogido como lo queremos pulsamos ok y esperamos que se cree, después lo seleccionamos y le damos a start y se nos abrirá otra ventana en la que seleccionamos scale display to real size para seleccionar el tamaño de nuestra pantalla del dispositivo y ponemos en screen size 7 que es un buen tamaño y pulsamos oky esperamos que se inicie

  • una vez arrancado nos dirigiremos a nuestro navegador y nos pondremos a instalar sl4a de android poniendo en google sl4a accediendo a la direccion que pone en la imagen


  • una vez dentro nos descargamos el archivo sl4a_r6 para la instalación del programa
Cuando se descargue lo instalamos y procedemos a descargar python para android poniendo en google python for android y accediendo al enlace descargamos el archivo llamado pythonforandroid_r5 y lo instalamos
  • una vez instalado accedemos a el programa python for android y pulsamos en browse modules y nos llevara a una pagina web donde descargaremos el archivo pytbluez y seguidamente volveremos a entrar en python for android y le daremos a import modules e importaremos este modulo descargado, después pulsaremos en la parte de arriba instal

  • una vez hecho todo esto crearemos en nuestro escritorio una carpeta y la llamaremos android o python for android

  • Descargamos el archivo python_extra_r14 en nuestro pc desde la pagina de andtes de python for android y lo extraemos, después accedemos a la carpeta idlelib y todo lo que contenga lo copiamos a la carpeta de nuestro escritorio android, no copiaremos la carpeta si no todo lo de dentro, lo seleccionamos todo, copiamos y pegamos en la carpeta del escritorio, también el archivo android.py de la carpeta anterior.

  • Despues nos vamos a C:/WINDOWS/system32 y buscamos el archivo llamado cmd.exe y le damos a enviar a escritorio(acceso directo)

  • Cuando este en el escritorio lo cortamos y lo pegamos en nuestra carpeta android, una vez dentro pulsamos en nuestro acceso directo cmd.exe y le damos botón derecho y propiedades y modificamos donde dice iniciar en y ponemos la ruta de nuestra carpeta copiando la ruta de donde dice dirección en nuestra carpeta pegándola donde dice iniciar en

  • Despues copiamos el archivo adb.exe y adbwinapi.dll de la carpeta de donde instalamos el sdk en C:\Android\platform-tools copiamos estos dos archivos y los pegamos en C:\WINDOWS\system32 

  • Ya lo tenemos todo preparado para empezar y abrimos nuestro sl4a en el emulador, una vez dentro de sl4a pulsamos en el botón menú y después en VIEW el la ventana que se abre abajo

  • Despues en interpreters, y volvemos a darle en el botón menú y pulsamos start server y pulsamos private y accedemos a ver que dirección va a usar para comunicarse con el pc

Ahora nos dirigimos a la carpeta que creamos en nuestro escritorio y ejecutamos el cmd.exe y ejecutamos lo siguiente:

1-adb forward tcp:9999 tcp:(direccion dispositivo android)
2-set AP_PORT=9999
3-idle.bat

se nos abrirá el idle de python y le damos a file y new windows y ya podemos empezar a escribir en nuestro idle de python y ver los resultados en nuestro emulador, por ejemplo veamos el típico mensaje de hola mundo poniendo lo siguiente:

import android
droid = android.Android()
droid.makeToast("hola mundo")









Programación Google App Engine con Python



Google App Engine o también conocido más comúnmente como GAE o App Engine nos abre la infraestructura de producción de Google de forma gratuita como plataforma de desarrollo y hospedaje de aplicaciones web.

El servicio fue lanzado el 7 de abril del 2008 como un servicio de cloud pero a diferencia de otros servicios en la nube como Amazon Web Services o Azure Services Platform de Microsoft, el servicio ofrecido por Google es un servicio de Plataforma como Servicio y no de Infraestructura como Servicio.



Características

GAE soporta de manera oficial los lenguajes de programación Python y Java de manera estable y en modo de beta testing en lenguaje de programación Go creado por ellos mismos. Al soportar Java, es posible además utilizar cualquier lenguaje JVM o lo que es lo mismo, cualquier lenguaje que pueda ejecutarse sobre una máquina virtual de Java, aunque eso si, con serias limitaciones. Entre dichos lenguajes se encuentran:

· Groovy

· JRuby

· Scala

· PHP

· Clojure

· Perl

GAE soporta varios frameworks bajo Python como CherryPy, Pylons, Flask y Django 0.96 y 1.2. Además la misma Google ha desarrrollado un framework propio llamado —viva la originalidad que les caracteriza— webapp para aplicaciones web que van mejorando y actualizando. También existe un framework desarrollado específicamente para GAE y siguiendo —supuestamente— la filosofía de Django llamado GAE framework.



Restricciones

· Las aplicaciones solo tienen permisos de lectura a los archivos del sistema de archivos. Para almacenar datos y archivos en modo lectura y escritura es necesario utilizar un sistema de archivos virtual sobre el DataStore.

· Solo se puede ejecutar código a través de consultas HTTP

· Las aplicaciones Java solo pueden usar el conjunto considerado seguro de clases del JREestándar. ( Comprueba el Listado de clases)

· Las aplicaciones no pueden crear nuevos hilos de ejecución

· Los usuarios de Python pueden subir módulos para su uso en la plataforma pero no aquellos que están completamente desarrollados en C o Pyrex

· El soporte para SSL solo está disponible par dominios *.appspot.com

· Un proceso iniciado en el servicio para responder a una consulta no puede durar más de treinta segundos

· No soporta sesiones persistentes, solo sesiones replicadas a las que además se les aplican ciertos límites.

· No se pueden abrir sockets, por lo tanto, no se puede usar Twisted



Introduccion con python

App Engine se ejecuta el código de aplicación Python usando un intérprete de pre-cargado de Python en un ambiente seguro "espacio aislado". Su aplicación recibe peticiones web, realiza un trabajo, y envía las respuestas mediante la interacción con este entorno.

Una aplicación web de Python interactúa con el servidor Web App Engine mediante el protocolo WSGI, por lo que las aplicaciones pueden utilizar cualquier framework de aplicaciones web compatibles con WSGI. App Engine incluye un marco de aplicación web sencilla, llamada webapp2, para hacer más fácil para empezar. Para aplicaciones más grandes, los marcos de terceros maduros, como Django, trabajar bien con App Engine.

El intérprete de Python puede ejecutar cualquier código Python, incluyendo módulos de Python que usted incluya con su solicitud, así como la biblioteca estándar de Python. El intérprete no puede cargar módulos de Python con el código C; se trata de un entorno de Python "puro".

El entorno de "sandbox" asegurado aísla su solicitud de servicio y seguridad. Asegura que las aplicaciones sólo pueden realizar acciones que no interfieren con el rendimiento y la escalabilidad de otras aplicaciones. Por ejemplo, una aplicación no puede escribir datos en el sistema de archivos local o realizar conexiones de red arbitrarias. En su lugar, las aplicaciones utilizan los servicios escalables proporcionadas por App Engine para almacenar datos y comunicarse a través de Internet. El intérprete de Python lanza una excepción cuando una aplicación intenta importar un módulo de la biblioteca estándar conocido para no trabajar dentro de las restricciones de entorno limitado.

La plataforma App Engine proporciona muchos servicios que su código puede llamar. Su aplicación también puede configurar tareas programadas que se ejecutan a intervalos especificados.

Selección del tiempo de ejecución de Python

App Engine sabe utilizar el entorno de ejecución de Python para el código de aplicación cuando se utiliza la herramienta llamadaappcfg.py desde el SDK de Python con un archivo de configuración llamado app.yaml

Se especifica el runtime los elementos de app.yaml Para utilizar Python 2.7, añada lo siguiente a app.yaml


runtime: python27


api_version: 1
threadsafe: true
...

Bibliotecas personalizadas en Python 2.7
Adición de Bibliotecas de terceros Python
El SDK y herramientas Python



El primer elemento, runtime selecciona el entorno de ejecución de Python.

El segundo elemento, api_version selecciona la versión del entorno de ejecución de Python para usar. Al escribir estas líneas, App Engine sólo tiene una versión del entorno de Python, 1 Si el equipo de App Engine nunca necesita liberar los cambios en el medio ambiente que pueden no ser compatibles con el código existente, lo harán con un nuevo identificador de versión. Su aplicación va a seguir utilizando la versión seleccionada hasta que cambie la api_version configuración y cargar su aplicación.

En el tiempo de ejecución de Python 2.7, los siguientes módulos han sido reemplazados o personalizada:

· tempfile está desactivado, a excepción de TemporaryFile que es un alias para StringIO.

· el registro está disponible y su uso es muy aconsejable! Ver registro.

Además de la biblioteca estándar de Python y las bibliotecas de App Engine, el tiempo de ejecución de Python 2.7 incluye variasbibliotecas de terceros.

Puede incluir terceros bibliotecas Python partido con su aplicación, poniendo el código en el directorio de la aplicación. Si comete un enlace simbólico al directorio de un módulo en el directorio de la aplicación, appcfg.py seguirá el enlace para insertar el módulo en su aplicación.

El módulo de Python incluye ruta incluye directorio raíz de la aplicación (el directorio que contiene el app.yaml archivo). Los módulos que se crean en el directorio raíz de la aplicación están disponibles con una ruta desde la raíz. No te olvides de crear __init__.pyarchivos en subdirectorios, así que Python reconocerá los subdirectorios como paquetes.

La App Engine Python SDK incluye herramientas para probar la aplicación, la posibilidad de subir sus archivos de la aplicación, la gestión de los índices del almacén de datos, la descarga de datos de registro, y la posibilidad de subir grandes cantidades de datos para el almacén de datos.

El servidor de desarrollo se ejecuta la aplicación en el equipo local para probar la aplicación. El servidor simula el almacén de datos de App Engine, servicios y restricciones sandbox. El servidor de desarrollo también puede generar la configuración del almacén de datos para los índices basados ​​en las consultas de la aplicación realiza durante la prueba.

Una herramienta multipropósito llamado appcfg.py maneja toda la interacción de línea de comandos con la aplicación que se ejecuta en App Engine. appcfg.py puede subir su aplicación en App Engine, o simplemente actualizar la configuración del índice de almacén de datos para que pueda construir nuevos índices antes de actualizar el código. También puede descargar los datos del registro de la aplicación, por lo que puede analizar el rendimiento de su aplicación utilizando sus propias herramientas.

REFERENCIAS
https://cloud.google.com/appengine/docs/python/

http://www.genbetadev.com/programacion-en-la-nube/introduccion-a-google-app-engine

http://www.genbetadev.com/programacion-en-la-nube/nuestra-primera-aplicacion-con-google-app-engine-python


lunes, 17 de agosto de 2015

Programación Web con Python


Aplicación Web con Python

Configuración del servidor Web

WebPy, a diferencia de otros frameworks, no posee un servidor de aplicaciones potente propio, y por ello, es mejor apoyarse en uno que ya esté funcionando. Entre los posibles candidatos se encuentran Apache, Lighttpd y nginx. Para este artículo he optado por Apache, dada su gran popularidad.

Una vez instalado Apache en nuestra máquina, es necesario agregar el módulo mod_wsgi, que permite hacer uso de Apache como servidor para aplicaciones escritas en Python. Este proyecto está alojado en: http://code.google.com/p/modwsgi

Una vez descargado, si estamos usando Windows, renombrar el archivo a mod_wsgi.so y copiarlo al directorio modules de Apache. En el caso de Linux, compilar el módulomod_wsgi (consultar: http://code.google.com/p/modwsgi/wiki/QuickInstallationGuide)

Una vez instalado el módulo, hay que configurar Apache para que reconozca dicho módulo. Para ello, editar el archivo httpd.conf (en el directorio conf de Apache), y agregar la siguiente línea en la misma parte en que Apache utiliza otras cargas LoadModule:

LoadModule wsgi_module modules/mod_wsgi.so

Al arrancar Apache desde la terminal debería dar un mensaje similar a éste:

Apache/2.2.2 (Unix) mod_wsgi/1.0 Python/2.3 configured

Si se lanzó desde Windows, el Apache Service Monitor, debería dar el mensaje en la parte inferior:





Instalación de WebPy

Hay varias maneras de instalar WebPy (consultar http://webpy.org/download).

Se puede descargar directamente la última versión desde la siguiente URL (consultarhttp://webpy.org/download para conocer cuál es la última versión):

http://webpy.org/static/web.py-0.34.tar.gz

También se puede descargar desde el repositorio en github:

http://github.com/webpy/webpy

Una vez descargado, descomprimir el archivo tar.gz, y ejecutar la siguiente sentencia para instalarlo como librería en Python:

python setup.py install


Primera aplicación Web

Para ilustrar la sencillez de desarrollo de una página Web con WebPy, vamos a crear la típica aplicación “Hola, Mundo”.

import web

urls = (
'/', 'index'
)

app = web.application(urls, globals())

class index:
def GET(self):
return "Hola, Mundo"

if __name__ == "__main__":
app.run()


La variable urls es una tupla que contiene pares de direccionamientos URL y nombres de clase. En este ejemplo, el direccionamiento “/” (root), estará asociado a la clase index. Se pueden definir tantos pares como sean necesarios para la aplicación Web.

El objeto app contendrá la definición de la aplicación Web. En este ejemplo se asocian las URL’s de la aplicación a namespace global.

La clase index contiene un método GET, el cual se lanzará cuando se invoque a la página, pudiendo recibir parámetros. En su interior, retornará el literal “Hola, Mundo”, el cual se imprimirá en el navegador. Existe también un método POST, que funciona como GET, pero ofuscando los parámetros. Estos dos métodos son los medios habituales de invocar a una página Web pasando (o no) parámetros.

Por último, las dos últimas líneas indican a WebPy que comience a servir páginas web con la configuración indicada.

Una vez se ejecuta este programa, el intérprete de Python se queda en modo de espera. El servicio Web está en marcha, esperando peticiones. Para probarlo, abrimos un navegador web e introducimos la URL:

http://localhost:8080

Debería aparecer nuestro bien conocido mensaje “Hola, Mundo”.


Parámetros y HTML

En una aplicación Web introduciremos elementos HTML para formatear el aspecto de las páginas. Además, añadiremos dinamismo permitiendo que las páginas muestren datos parametrizados (por ejemplo, recogidos de un formulario, o capturados de una base de datos).

Vamos a añadir más funcionalidad a nuestra aplicación anterior:

import web

urls = (
'/hola', 'Saludo'
)

app = web.application(urls, globals())

class Saludo:
def GET(self):
data = web.input()
return """
<html>
<head></head>
<body background='#AAAAFF'>
<h1>Hola, %s %s %s</h1>
</body>
</html>""" % (data.nombre, data.apellido1, data.apellido2)

if __name__ == "__main__":
app.run()

El primer cambio lo hemos realizado en la sección de urls, donde ahora, el mapeo a la página Web será el siguiente:

http://localhost:8080/hola

Cuando se apunta a /hola, se invocará a la clase Saludo, concretamente a su método GET, en donde hemos agregado varios cambios. El primero de ellos ha sido definir una variabledata, la cual recogerá los parámetros que se pasen por URL, lo que se consigue mediante la función input() del módulo web. Estos parámetros se recogerán en formato de diccionario, y son pares de parámetro y valor.

A la hora de retornar la salida, se retornará HTML, en donde hemos añadido un mensaje con formato de título (<h1>), un saludo con nombre y apellidos (extraídos de los parámetros pasados), los cuales se formatean mediante %s, e indicando después qué parámetros extraer.

Para invocar a la nueva página se pasan los parámetros en la misma URL, tal y como haría una llamada desde un formulario:

http://localhost:8080/hola?nombre=Carmen&apellido1=Martinez&apellido2=Salguero

El resultado es el siguiente:





Referencias

https://librosweb.es/libro/python/capitulo_13/python_bajo_apache.html

http://rafinguer.blogspot.mx/2010/10/aplicaciones-web-sencillas-con-python.html