Python: Queue.Empty Manejo de excepciones

Después de un breve debate con alguien sobre el manejo de excepciones en Python, provocado por el manejo de un objeto de cola, pensé que lo tiraría por ahí …

MÉTODO 1:

import Queue q = Queue.Queue() try: task=q.get(False) #Opt 1: Handle task here and call q.task_done() except Queue.Empty: #Handle empty queue here pass #Opt2: Handle task here and call q.task_done() 

MÉTODO 2:

 import Queue q = Queue.Queue() if q.empty(): #Handle empty queue here else: task = q.get() #Handle task here q.task_done() 

Un argumento es que el Método 1 es incorrecto porque la cola que está vacía no es un error y, por lo tanto, no debe manejarse con la excepción Queue.Empty. Además, podría hacer que la depuración sea más difícil cuando se codifica de esta manera si considera que la parte de manejo de tareas podría ser potencialmente grande.

El otro argumento es que de cualquier manera es aceptable en Python y que el manejo de la tarea fuera del bash / excepto podría ayudar a depurar si el manejo de la tarea es grande, aunque se acordó que esto podría parecer más feo que usar el Método 2.

Opiniones?

ACTUALIZACIÓN: Un poco más de información después de que llegó la respuesta 1 … El debate se inició después de que el método 1 se usara en algunos códigos de multiproceso. En cuyo caso, el código adquirirá el locking (de un objeto threading.Lock) y lo liberará una vez que se haya lanzado la tarea que devolvió o Queue.Empty

ACTUALIZACIÓN 2: Los dos desconocíamos que el objeto de cola era seguro para subprocesos. Parece que intentar / excepto es el camino a seguir!

El método 2 es incorrecto porque está realizando una operación en dos pasos cuando podría hacerse en uno. En el método 2, verifica si la cola está vacía, y luego (muy pronto, pero aún más tarde), intenta obtener el artículo. ¿Qué pasa si tienes dos hilos que extraen elementos de la cola? El get () todavía podría fallar con una cola vacía. ¿Qué sucede si se agrega un elemento a la cola después de verificar que estaba vacío? Estos son el tipo de pequeñas ventanas de oportunidad donde los errores se arrastran al código concurrente.

Hazlo en un solo paso, es por mucho la mejor opción.

 import Queue q = Queue.Queue() try: task = q.get(False) except Queue.Empty: # Handle empty queue here pass else: # Handle task here and call q.task_done() 

No se obsesione con “las excepciones deben ser errores”. Las excepciones son simplemente otro canal de comunicación, utilízalos. Use la cláusula “else” aquí para restringir el scope de la cláusula de excepción.

Si este es un código multiproceso / multiproceso (como es una buena razón para usar colas), entonces definitivamente el método 1. Entre la llamada q.empty() y la llamada q.get() , Jack of Hearts podría haber robado tus tartas !

Un argumento es que el Método 1 es incorrecto porque la cola que está vacía no es un error y, por lo tanto, no debe manejarse utilizando la excepción Queue.Empty

Una excepción no es necesariamente un “error”, es un mecanismo general de control de flujo y, de hecho, se usa de esa manera en algunos casos (SysExit, StopIteration, etc.).

La buena pregunta aquí es: cuál será el caso más común: cola vacía o no vacía. A menos que esté seguro, desea preguntar antes de que usted salte, porque es muy probable que sea mucho más barato.