¿Cómo solucionar un "AttributeError: __exit__" en multiprocesamiento en Python?

87

Intenté reescribir un código de lectura csv para poder ejecutarlo en varios núcleos en Python 3.2.2. Traté de usar el Poolobjeto de multiprocesamiento, que adapté de ejemplos de trabajo (y ya me funcionó para otra parte de mi proyecto). Me encontré con un mensaje de error que encontré difícil de descifrar y solucionar.

El error:

Traceback (most recent call last):
  File "parser5_nodots_parallel.py", line 256, in <module>
    MG,ppl = csv2graph(r)
  File "parser5_nodots_parallel.py", line 245, in csv2graph
    node_chunks)
  File "/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/multiprocessing/pool.py", line 251, in map
    return self.map_async(func, iterable, chunksize).get()
  File "/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/multiprocessing/pool.py", line 552, in get
    raise self._value
AttributeError: __exit__

El código relevante:

import csv
import time
import datetime
import re
from operator import itemgetter
from multiprocessing import Pool
import itertools

def chunks(l,n):
    """Divide a list of nodes `l` in `n` chunks"""
    l_c = iter(l)
    while 1:
        x = tuple(itertools.islice(l_c,n))
        if not x:
            return
        yield x

def csv2nodes(r):
    strptime = time.strptime
    mktime = time.mktime
    l = []
    ppl = set()
    pattern = re.compile(r"""[A-Za-z0-9"/]+?(?=[,\n])""")
    for row in r:
        with pattern.findall(row) as f:
            cell = int(f[3])
            id = int(f[2])
            st = mktime(strptime(f[0],'%d/%m/%Y'))
            ed = mktime(strptime(f[1],'%d/%m/%Y'))
        # collect list
        l.append([(id,cell,{1:st,2: ed})])
        # collect separate sets
        ppl.add(id)
    return (l,ppl)

def csv2graph(source):
    MG=nx.MultiGraph()
    # Remember that I use integers for edge attributes, to save space! Dic above.
    # start: 1
    # end: 2
    p = Pool()
    node_divisor = len(p._pool)
    node_chunks = list(chunks(source,int(len(source)/int(node_divisor))))
    num_chunks = len(node_chunks)
    pedgelists = p.map(csv2nodes,
                       node_chunks)
    ll = []
    ppl = set()
    for l in pedgelists:
        ll.append(l[0])
        ppl.update(l[1])
    MG.add_edges_from(ll)
    return (MG,ppl)

with open('/Users/laszlosandor/Dropbox/peers_prisons/python/codetenus_test.txt','r') as source:
    r = source.readlines()
    MG,ppl = csv2graph(r)

¿Cuál es una buena forma de solucionar este problema?

László
fuente
1
En mi caso, accidentalmente pasé un Nonedebido a problemas de alcance.
ThorSummoner
Tuve esto cuando estaba declarando una clase Class SomeClass(object):a pesar de que TENÍA explícitamente una salida en mi clase. Una vez que eliminé la herencia objectfuncionó. No tengo idea de por qué, entonces YMMV
mpag

Respuestas:

155

El problema está en esta línea:

with pattern.findall(row) as f:

Estás usando la withdeclaración. Requiere un objeto con métodos __enter__y __exit__. Pero pattern.findalldevuelve a list, withintenta almacenar el __exit__método, pero no puede encontrarlo y genera un error. Solo usa

f = pattern.findall(row)

en lugar.

utdemir
fuente
63

No es el problema del autor de la pregunta en esta instancia, pero el primer paso de solución de problemas para un "AttributeError: __exit__" genérico debe ser asegurarse de que los corchetes estén allí, por ejemplo

with SomeContextManager() as foo:
    #works because a new object is referenced...

no

with SomeContextManager as foo:
    #AttributeError because the class is referenced

Me atrapa de vez en cuando y termino aquí -__-

Bolsillos y
fuente
9

El error también ocurre al intentar utilizar el

with multiprocessing.Pool() as pool:
   # ...

con una versión de Python que es demasiado antigua (como Python 2.X) y no admite el uso withjunto con grupos de multiprocesamiento.

(Consulte esta respuesta https://stackoverflow.com/a/25968716/1426569 a otra pregunta para obtener más detalles)

oseiskar
fuente
¡Sí! Funciona muy bien en Python 3.X
Sreekant Shenoy
-1

La razón detrás de este error es: la aplicación Flask ya se está ejecutando, no se ha cerrado y, en medio de eso, intentamos iniciar otra instancia mediante: con app.app_context (): #Code Antes de usar esto con la declaración que necesitamos hacer asegúrese de que el alcance de la aplicación en ejecución anterior esté cerrado.

SIDDHARTH SETHIA
fuente