Python R2


Jugando con Automatas en Python (AFN -> AFD)

Después de tanto tiempo de no escribir y ya preparando la charla para dar en la FLISOL de  Carmelo me puse a jugar un poco con autómatas (Talvez muestre algo de esto allá). Este script lo que hace es bastante simple transforma un autómata finito no determinista a un autómata finito determinista. 😉 Saludos y espero que les guste.

#!/usr/bin/python
# Clase AFN para transformar un AFN en un AFD

class AFN:
    def __init__(self,AFN):
        self.AFN = AFN
        self.SimbolosDelLenguaje =  self.LenguajeDeAFN()
        self.AFD = self.ToAFD()
    def Transaccion(self,e,t):
        return filter(lambda s:s[0]==t,filter(lambda s:s[0]==e,self.AFN)[0])[0][1]

    def EstadoInicial(self):
        # retorna una lista con el unico estado inicial
        return filter(lambda s:len(s)>=4 and s[3]=='>',self.AFN) #simpre tendria que ser uno por definicion de automatas

    def LenguajeDeAFN(self):
        # simbolos del lenguaje del AFN
        return [l[0] for l in  filter(lambda s:len(s)==2,self.AFN[-1])];

    def EstadosTratados(self):
        return [e[0] for e in  self.AFD] # los estados de llegada que fueron tratados

    def EstadosNoTratados(self):
        return map(lambda e:e[1],filter(lambda s:s[0] in self.SimbolosDelLenguaje and s[1] not in self.EstadosTratados(),self.AFD[-1]))

    def ToAFD(self):
        self.AFD =[]
        vecEstTmp= self.EstadoInicial()

        while len(vecEstTmp) <> 0:
            self.AFD.append( vecEstTmp[0])
            for estado in self.EstadosNoTratados(): #se recorren todos los estados que no fueron tratados
                TransaccionDelAFD=[] #en este vector se calculara los  las transacciones del AFD resultantes
                for simbolo in self.SimbolosDelLenguaje: # recorro para todos los simbolos del lenguaje
                    nuevoEstado=[]                       # defino nuevoEstado para armar el nuevo estado del AFD
                    for e in estado:                     # calculo la union con los conjuntos de llegada de todos los estados
                        for t in self.Transaccion([e],simbolo):
                            if t not in nuevoEstado:
                                nuevoEstado.append(t)
                        nuevoEstado.sort()

                    TransaccionDelAFD.append([simbolo,nuevoEstado])

                vecEstTmp.append([estado]+TransaccionDelAFD)

            vecEstTmp.pop(0)

        #busco los estados de Aceptacion y le pongo el *
        estasdosDeAceptacion = [l[0][0] for l in filter(lambda s:len(s)>=4 and s[-1]=='*',self.AFN)] #estados de Aceptacion
        for e in self.AFD:
            Aceptacion = False
            for ea in estasdosDeAceptacion :
                        if not Aceptacion:
                            Aceptacion =  ea in e[0]
            if Aceptacion and '*' not in e: e.append('*')

        return self.AFD

AUT = AFN(
        [
        [ [1], ['a',[1]] ,['b',[1,2]],'>'],
        [ [2], ['a',[] ] ,['b',[3]  ]],
        [ [3], ['a',[3]] ,['b',[3]  ],'*']
        ]#tabla de trancicion marcando con una -> el estado inicial y con * los estados favorables
        )

for l in  AUT.AFD:
    print l
Anuncios

Introduccion a Python – OpenCV

Posted in Python por Arturo Elias Antón en 8 febrero 2009
Tags: , , , , ,

Vamos a reconocer el rostro de nuestros usuario y dentro de el los ojos y la boca y la nariz. Para esto en esta oportunidad vamos a utilizar una biblioteca llamada opencv.

Acá les dejo el código

#!/usr/bin/python

import pygame
import Image
from pygame.locals import *
import opencv
from opencv import adaptors
from opencv import highgui,cv

def sincroImg(image,scale):
	image_size  = cv.cvGetSize(image)
	grayscale   = cv.cvCreateImage(image_size, 8, 1)
	image_small = cv.cvCreateImage(cv.cvSize(cv.cvRound(image.width/scale),cv.cvRound(image.height/scale)), 8, 1)
	cv.cvCvtColor(image, grayscale, cv.CV_BGR2GRAY)
	cv.cvResize(grayscale,image_small,cv.CV_INTER_LINEAR)
	cv.cvEqualizeHist(grayscale, grayscale)
    	return grayscale

def dectect(img,cascade,storage,x,y,scale):
	cv.cvClearMemStorage(storage)
	return cv.cvHaarDetectObjects(
                                   img,
                                   cascade,
                                   storage,
                                   scale,
                                   2,
                                   0,#cv.CV_HAAR_DO_CANNY_PRUNING,
                                   cv.cvSize(x, y))

camara = highgui.cvCreateCameraCapture(0)

fps = 30
pygame.init()
ventana = pygame.display.set_mode((320,240))
pygame.display.set_caption("OpenCV + Webcam Test")
screen = pygame.display.get_surface()

print "OpenCV version: %s (%d, %d, %d)" % (cv.CV_VERSION,
                                               cv.CV_MAJOR_VERSION,
                                               cv.CV_MINOR_VERSION,
                                               cv.CV_SUBMINOR_VERSION)

cascade_name       ='xml/haarcascade_frontalface_alt.xml'
cascade_name_nariz ='xml/nariz.xml'
cascade_name_ojos  ='xml/ojos.xml'
cascade_name_boca  ='xml/boca.xml'
storage = cv.cvCreateMemStorage(0)

cascade = cv.cvLoadHaarClassifierCascade(cascade_name, cv.cvSize(14,14))
cascade_nariz = cv.cvLoadHaarClassifierCascade(cascade_name_nariz, cv.cvSize(14,14))
cascade_ojos = cv.cvLoadHaarClassifierCascade(cascade_name_ojos, cv.cvSize(22,22))
cascade_boca = cv.cvLoadHaarClassifierCascade(cascade_name_boca, cv.cvSize(25,15))

scale = 2
inx=0
while True:
	img1 = highgui.cvQueryFrame(camara)

        # face detection
	sincroImg(img1,scale)
        faces = dectect(img1,cascade,storage,50,50,scale)
	b_ojos = False
	b_boca = False
	b_nariz= False
	if faces.total != 0:
		face = faces[0]
		cv.cvRectangle(img1,
			cv.cvPoint( int(face.x), int(face.y)),
			cv.cvPoint(int(face.x + face.width), int(face.y + face.height)),
			cv.CV_RGB(255,0,0), 3, 8, 0)
		face_x1 = int(face.x)
		face_y1 = int(face.y)
		face_x2 = int(face.x + face.width)
		face_y2 = int(face.y + face.height)

		ojos  = dectect(img1,cascade_ojos,storage,20,20,scale)
		for o in ojos:
			if o.x > face_x1 and o.y > face_y1 and (o.x + o.width) < face_x2 and  (o.y + o.height) < face_y2:
				cv.cvRectangle(img1,
					cv.cvPoint( int(o.x), int(o.y)),
					cv.cvPoint(int(o.x + o.width), int(o.y + o.height)),
					cv.CV_RGB(0,0,255), 3, 8, 0)
				ojos_x1= o.x
				ojos_y1= o.y
				ojos_x2= o.x + o.width
				ojos_y2= o.y + o.height
				b_ojos=True;
		bocas =[]
		if b_ojos:bocas  = dectect(img1,cascade_boca,storage,60,30,scale)
		for b in bocas:
			if b.x > ojos_x1 and b.y > ojos_y2 and (b.x + b.width) < ojos_x2 and  (b.y + b.height) < face_y2:
				cv.cvRectangle(img1,
					cv.cvPoint( int(b.x), int(b.y)),
					cv.cvPoint(int(b.x + b.width), int(b.y + b.height)),
					cv.CV_RGB(0,255,0), 3, 8, 0)
				boca_x1= b.x
				boca_y1= b.y
				boca_x2= b.x + b.width
				boca_y2= b.y + b.height
				b_boca= True

		narices =[]
		if b_boca:narices  = dectect(img1,cascade_nariz,storage,40,40,scale)
		for n in narices:
			if n.x > ojos_x1 and n.y < boca_y1 and n.y >= ojos_y2 and n.x + n.width < ojos_x2 :
				cv.cvRectangle(img1,
					cv.cvPoint( int(n.x), int(n.y)),
					cv.cvPoint(int(n.x + n.width), int(n.y + n.height)),
					cv.CV_RGB(0,0,0), 3, 8, 0)
				b_nariz = True

	img = adaptors.Ipl2PIL(img1).resize((320,240))

	if b_nariz:
		img.save('img/img'+str(inx)+'.jpg')
		inx+=1

	pgimg = pygame.image.frombuffer(img.tostring(), img.size, img.mode)
    	screen.blit(pgimg, (0,0))
    	pygame.display.flip()
    	pygame.time.delay(int(1000 * 1.0/fps))

Espero que les guste 🙂

Aca dejo un tar.gz con todos los xml necesarios y algunos otros para que prueben

Link a haarcascades(XMLs): xml.tar.gz

No se olviden de anotarse al grupo binsd de google 😛

Buscando caminos con python

Uno de los problemas que me enfrente hoy era aun pequeño mapa donde yo tenía que pasarle la ciudad origen y destino  y mi py tenia que contestar con el camino mas corto posible. buscando en google encontre este link:
http://www.cruzrojaguayas.org/inteligencia/B%FAsqueda%20respaldados%20con%20informaci%F3n.htm

y basándome en el ejemplo de Algoritmo A* hice esto.

Mapa

Mapa

Acá un mapa con las ciudades. (Perdón por mi ignorancia geográfica) 🙂

Y acá el script.

#!/usr/bin/env python
#Archivo: buscadorDecaminos.py
from mapa import Puntos, Mapa

mapa    = Mapa()
mapa.add(Puntos("Capital Federal"))
mapa.add(Puntos("Santa Fe"))
mapa.add(Puntos("Rosario"))
mapa.add(Puntos("Parana"))
mapa.add(Puntos("San Luis"))
mapa.add(Puntos("Cordoba"))
mapa.add(Puntos("Mendoza"))
mapa.add(Puntos("Tucuman"))

mapa.puntos["Capital Federal"].add(mapa.puntos["Rosario"],320)
mapa.puntos["Capital Federal"].add(mapa.puntos["Cordoba"],716)
mapa.puntos["Rosario"].add(mapa.puntos["Parana"],175)
mapa.puntos["Rosario"].add(mapa.puntos["Santa Fe"],150)
mapa.puntos["Rosario"].add(mapa.puntos["Cordoba"],398)
mapa.puntos["Santa Fe"].add(mapa.puntos["Parana"],29)
mapa.puntos["Cordoba"].add(mapa.puntos["Tucuman"],534)
mapa.puntos["Cordoba"].add(mapa.puntos["Mendoza"],617)
mapa.puntos["Cordoba"].add(mapa.puntos["San Luis"],413)

print "Capital Federal -> Parana:",mapa.camino("Capital Federal","Parana")
print "Capital Federal -> San Luis:",mapa.camino("Capital Federal","San Luis")
print "Tucuman         -> Capital Federal:",mapa.camino("Tucuman","Capital Federal")
print "Tucuman         -> Mar del plata  :",mapa.camino("Tucuman","MDQ")

y aca el modulo mapa

#!/usr/bin/env python
#Archivo: mapa.py
class Puntos:
    def __init__(self,nombre):
        self.relaciones = {}
        self.nombre = nombre
        self.max = 0

    def add(self,p,d,b = True):
        self.relaciones[p.nombre] = [p,d]
        if b: p.add(self,d,False)

    def caminoA(self,hasta,recorrido=0,recorridas=[],camino=[]):

        minimo = None;

        if hasta == self.nombre:
            return  [recorrido,[self.nombre]] # estoy en la ciudad wiiiiiii

        recorridas.append(self.nombre)      # pase por aca
        nodosHijos = filter(lambda x:not x in recorridas, self.relaciones) #mis hijos por los cuales no pase son
        if nodosHijos == []: return ["Fallo","Fallo"] # 😦 no llegue a ningun lado

        for p in nodosHijos:
            datos = self.relaciones[p][0].caminoA(hasta,self.relaciones[p][1],recorridas)
            if (datos[0] != "Fallo") and  (datos[0] < minimo or minimo == None):
                minimo = datos[0]
                nodoElegido = datos[1]

        try: # si no existe nodoElegido
            nodoElegido.insert(0, self.nombre)
        except: # Fallo
            return ["Fallo","Fallo"]

        return [recorrido + minimo,nodoElegido]

class Mapa:
    def __init__(self):
        self.puntos = {}

    def add(self,p):
        self.puntos[p.nombre]=p

    def camino(self,desde,hasta):
        return self.puntos[desde].caminoA(hasta,0,[],[])

La salida es:

>>>
Capital Federal -> Parana: [495, ['Capital Federal', 'Rosario', 'Parana']]
Capital Federal -> San Luis: [1129, ['Capital Federal', 'Cordoba', 'San Luis']]
Tucuman         -> Capital Federal: [1250, ['Tucuman', 'Cordoba', 'Capital Federal']]
Tucuman         -> Mar del plata  : ['Fallo', 'Fallo']
>>>

Como siempre espero que les guste y les sirva

Modulos en python

Posted in Python por Arturo Elias Antón en 6 septiembre 2008
Tags: , , , , ,

Un módulo es una colección de funciones procedimientos y clases en un fichero que acaba en “.py”. El nombre del fichero determina el nombre del módulo. Para poder usar los contenidos del modulo que creemos simplemente lo tendremos que importarlo con la palabra reservada “import”.

Por ejemplo armaremos un archivo llamado cuadratica.py

# Nombre : cuadratica.py
import math

def determinante(a,b,c):
    return (b*b)-(4*a*c)

def calculaRaiz(a,b,c):
    det = determinante(a,b,c)
    if det < 0:
        print "tiene raices imaginarias"
    else:
        print "La rais 1 es " + str((b + math.sqrt(det))/(2*a))
        print "La rais 2 es " + str((b - math.sqrt(det))/(2*a))

Y luego lo usaremos en el archivo usa_modulo.py

#!/usr/bin/python
# Nombre : usa_modulo.py
import cuadratica
cuadratica.calculaRaiz (3,9,6)

Otra forma de uso o mejor dicho de invocación del modulo es invocar solo la función que necesitamos de dicho modulo. Esto nos da la ventaja de que no tendremos que poner el nombre del modulo antes de la función que queramos invocar.

#!/usr/bin/python
# Nombre : usa_modulo2.py
from cuadratica import calculaRaiz
calculaRaiz(3,9,6)

Sincronización de hilos en python

Para poder sincronizar el acceso de nuestros hilos, en modulo de threading nos facilita estos métodos de sincronización : mutex, locks re-entrantes, semáforos, condiciones y eventos.

Mutex o locks o Candados

Realmente los mutex son la herramienta más fácil que hay de sintonización. Un mutex se usa en programación concurrente para que un solo procesos o hilo en nuestro caso pueda tomar un recurso compartido por otros. La parte de código que toma dicho recurso se llama sección crítica. El mutex solo puede tomar dos estados que son tomados y liberado. Miremos un ejemplo para aclarar las ideas.

En el archivo mutex.py y compare su salida con el de hilo.py de la entrada anterior

#!/usr/bin/python
# Nombre de Fichero : mutex.py

import threading
from time import sleep
mutex = threading.Lock()
class Hilo(threading.Thread):
    def __init__(self, id):
        threading.Thread.__init__(self)
        self.id = id

    def run(self):
        mutex.acquire()
        sleep(3-self.id)
        print "Yo soy %s la variable d tiene el valor %s"%(self.id,d)
        mutex.release()

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

for h in hilos:
    h.start()

Bueno veremos otro ejemplito llamado mutex1.py

#!/usr/bin/python
# Nombre de Fichero : mutex.py

import threading
from time import sleep
mutex = threading.Lock()

n=0
class Hilo(threading.Thread):
    def __init__(self, id):
        threading.Thread.__init__(self)
        self.id = id

    def run(self):
        mutex.acquire()
        sleep(3-self.id)
        d.append(self.id)
        mutex.release()

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

for h in hilos:
    h.start()

mutex.acquire()
print d
mutex.release()

comparemos la salida con mutex.acquire() y sin él. Recorrar que por cada mutex.acquire() que sacamos tenderemos que sacar tambien el mutex.release()
sino se nos quedara bloqueado el hilo de ejecución. Igual mente me parece que esta buene que vean como se bloquea al sacar el release.

locks re-entrantes – Rlook
La clase RLock es similar a Lock, pero puede ser adquirido por el mismo thread varias veces, y no quedará liberado hasta que el thread lo libere tantas veces como llamó a acquire.

Los semáforos

Los semáforos son parecidos a los mutex pero en vez de tomar el valor 1 y 0, toman n valores que nos indicara la cantidad de hilos, que puede tomar el recurso concurrentemente. Para esto python nos facilita la clase Semaphore y BoundedSemaphore. La diferencia de 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

Miremos este ejemplo llamado semaphore.py

#!/usr/bin/python
# Nombre de Fichero : semaphore.py

import threading
from time import sleep
semaforo = threading.Semaphore(2)

n=0
class Hilo(threading.Thread):
    def __init__(self, id):
        threading.Thread.__init__(self)
        self.id = id

    def run(self):
        semaforo.acquire()
        sleep(3-self.id)
        d.append(self.id)
        semaforo.release()

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

for h in hilos:
    h.start()

sleep(4)
semaforo.acquire()
print d
semaforo.release()

fijese que si agrega justo antes del sleep(4) 3 release como estos

semaforo.release()
semaforo.release()
semaforo.release()

La salida cambia de orden ya que entra mas de uno hilo concurrente.
En cambio si después de agregar estas tres lineas, cambiamos la linea
semaforo = threading.Semaphore(2) por semaforo = threading.BoundedSemaphore(2)
dara error de tipo ValueError.

Las condiciones

Las condiciones son de utilidad para hacer que los threads sólo puedan entrar en la sección crítica de darse una cierta condición o evento.La clase condition tiene métodos wait, notify y notifyAll.

El método wait debe llamarse después de haber adquirido el objeto condiction con acquire. Este método libera el candado y bloquea al hilo hasta que una llamada a notify o notifyAll en otro hilo le indican que se ha cumplido la condición. El hilo que informa a los demás de que se ha producido la condición, también debe llamar a acquire antes de llamar a notify o notifyAll.

Espero que el ejemplo del archivo condition.py sea ilustrativo.

#!/usr/bin/python
# Nombre de Fichero : condition.py
import threading

cond = threading.Condition()

class Cliente (threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
    def run(self):
        while True:
            cond.acquire()
            cond.wait()
            mesa.pop()
            cond.notify()
            cond.release()

class Cosinero(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
    def run(self):
        while True:
            cond.acquire()
            if len(mesa) != 0: cond.wait()
            mesa.append("Torta de frutillas")
            cond.notify()
            cond.release()

print "El bar"

mesa = []
cliente = Cliente()
cosinero = Cosinero()

cliente.start()
cosinero.start()

while True:
    print mesa

acquire no bloqueante

Para que acquire no bloque el hilo le tenemos que pasar (False) como parámetro. Dicha invocación nos dará el resultado de si obtuvo el hilo o no. Modificaremos el ejemplo del mutex para que se vea lo que pasa.

#!/usr/bin/python
# Nombre de Fichero : mutex2.py

import threading
from time import sleep
mutex = threading.Lock()
class Hilo(threading.Thread):
    def __init__(self, id):
        threading.Thread.__init__(self)
        self.id = id

    def run(self):
        b = mutex.acquire(False)
        print b
        sleep(3-self.id)
        print "Yo soy %s la variable d tiene el valor %s"%(self.id,d)
        if b :mutex.release()

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

for h in hilos:
    h.start()

Los eventos

La clase Event es un wrapper por encima de Condition y sirven principalmente para coordinar threads mediante señales que indican los eventos que han ocurrido. Los no tienen los métodos acquire y release.
El hilo que debe esperar el evento se pondra en espera por medio de la llama al método wait y se bloquea, le podriamos pasar como parámetro un número en coma flotante indicando el número máximo de segundos a esperar. Otro hilo, cuando ocurre el evento, envía la señal a los hilos bloqueados a la espera de dicho evento utilizando el método set. Los hilos que estaban esperando se desbloquean una vez recibida la señal. La bandera que indica si se ha producido el evento se puede volver a setar a falso usando clear. Los eventos son similares a las condiciones.

Un ejemplo lo vemos en eventos.py que es una modificación de condition.py

#!/usr/bin/python
# Nombre de Fichero :  eventos.py
import threading

evento = threading.Event()

class Cliente (threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
    def run(self):
        while True:
            self.evento.wait()
            mesa.pop()

class Cosinero(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
    def run(self):
        while True:
            if len(mesa) != 0: cond.wait()
            mesa.append("Torta de frutillas")
            evento.set()

print "El bar"

mesa = []
cliente = Cliente()
cosinero = Cosinero()

cliente.start()
cosinero.start()

while True:
    print mesa

Hilos en Python

Posted in Python por Arturo Elias Antón en 1 septiembre 2008
Tags: , , , , , , ,

Sacando el tema que a los hilos le dice hebras por un problema de traducción en el libro de Silberschatz esta bien explicado que es un hilo. Y de hay esta definición:

“Una hebra  es una unidad básica de utilización de la CPU; comprende un ID de hebra, un contador de programa, un conjunto de registros y una pila. Comparte con otras hebras que pertenecen al mismo proceso la sección de código, la sección de datos y otros recursos del sistema operativo, como los archivos abiertos y las señales. Un proceso tradicional (o un proceso pesado) tiene una sola hebra de control. Si un proceso tiene, por lo contrario, múltiples hebras de control, puede realizar más de una tarea  a la vez.”   [Fundamentos de sistemas operativos (Septina edicion en Español), Atutores: Silberschatz, Galván, Gagne ISBN: 84-481-4641-7 Editorial McGraw-Hill]

Otra buena explicación la da Andrew S. Tanenbaum en su libro Sistemas Operativos Modernos. Diciendo:

“En la mayoría de los sistemas operativos tradicionales, cada proceso tiene un espacio de direcciones y un único hilo de control. De hecho, esa es casi la definición de un proceso. Sin embargo, con frecuencia existen situaciones en donde se desea tener varios hilos de control que compartan un único espacio de direcciones, pero que ejecutan de manera quasi-paralela, como si fuera de hecho procesos independientes (excepto por el espacio de direcciones compartido)” [Sistemas Operativos Modernos Autor: Andrew S. Tanenbaum ISBN: 968-880-323-5 Editorial: Prentice Hall]

Si seguimos leyendo en ente ultimo libro también nos explicara par que inventaron los hilos diciendo.

“Los hilos se inventaron para permitir la combinación del paralelismo con la ejecución secuencial y el bloqueo de las llamadas al sistema” [Sistemas Operativos Modernos Autor: Andrew S. Tanenbaum ISBN: 968-880-323-5 Editorial: Prentice Hall]

Bueno basta de citas y de libros, si están leyendo esto es por que quieren hacer hilos en python. Para esto tendremos que importar el paquete threading. Y luego crear una clase que herede de threading.Thread.  Si queremos que esta clase tenga un constructor propio tendrá que invocar también al constructor de Thread.  Esto lo hace invocando a threading.Thread.__init__(self).
Dentro de la clase rescribiremos el método run. Y dentro de el pondremos el código que queramos que ejecute nuestro hilo.
Luego instanciaremos un objeto con nuestra clase. Y para que empiece a ejecutar solo tendremos que invocar al método start de nuestro objeto.

Un ejemplo simple podría ser el de hilo.py

#!/usr/bin/python
# Nombre de Fichero : hilo.py
import threading
from time import sleep

class Hilo(threading.Thread):
    def __init__(self, id):
        threading.Thread.__init__(self)
        self.id = id

    def run(self):
        sleep(3-self.id)
        print "Yo soy %s la variable d tiene el valor %s"%(self.id,d)

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

for h in hilos:
    h.start()

fijemosnos que todos los hilos comparten la variable d.

Mirando en la lista de pyar vi un mail que decía como ejecutar dos programas secuenciales. Y se me ocurrió que podría hacerlo con hilos. Acá esta el código que hice espero que alguien le sirva.

#!/usr/bin/python
# Nombre de Fichero : lote.py
import threading
from os import system
from time import sleep

class Trabajo(threading.Thread):
    """
    Esta es la clase Trabajo. Los Trabajos  se pueden ejecutar de 4 maneras
    Que esperen a estar solos para ejecutarse.
    Que esperen a estar solos para ejecutarse y no dejar ejecutar ningun otro hasta terminar.
    Que no dejen ejecutar a ninguno otro hasta terminar.
    Que se ejecuten sin restricciones mientras los otros lo dejen
    """
    def __init__(self, id, cmd, entroSolo = False ,salgoSolo = False):
        threading.Thread.__init__(self)
        self.cmd = cmd
        self.id = id
        self.entroSolo = entroSolo
        self.salgoSolo = salgoSolo

    def run(self):
        system(self.cmd)

print "lotePy  0.0.1"

tabajos = [Trabajo(1,"calc",True,True),
           Trabajo(2,"Notepad",True),
           Trabajo(3,"dir c:\\",True)]

for t in tabajos:
    while (t.entroSolo)  and (threading.activeCount() != 1):pass
    t.start()
    if (t.salgoSolo):
        t.join()

En la próxima entrada veremos como el tema de sincronización.