¿Qué haría que WordNetCorpusReader no tuviera ningún atributo LazyCorpusLoader?

Tengo una función corta para verificar si una palabra es una palabra real comparándola con el corpus de WordNet del Natural Language Toolkit. Estoy llamando a esta función desde un hilo que valida los archivos txt. Cuando ejecuto mi código, la primera vez que se llama a la función lanza un AttributeError con el mensaje

"'WordNetCorpusReader' object has no attribute '_LazyCorpusLoader__args'" 

Cuando hago una pausa en la ejecución, la misma línea de código no arroja un error, por lo que asumo que el corpus aún no está cargado en mi primera llamada que causa el error.

He intentado usar nltk.wordnet.ensure_loaded() para forzar la carga del corpus, pero sigo recibiendo el mismo error.

Aquí está mi función:

 from nltk.corpus import wordnet as wn from nltk.corpus import stopwords from nltk.corpus.reader.wordnet import WordNetError import sys cachedStopWords = stopwords.words("english") def is_good_word(word): word = word.strip() if len(word) <= 2: return 0 if word in cachedStopWords: return 0 try: wn.ensure_loaded() if len(wn.lemmas(str(word), lang='en')) == 0: return 0 except WordNetError as e: print "WordNetError on concept {}".format(word) except AttributeError as e: print "Attribute error on concept {}: {}".format(word, e.message) except: print "Unexpected error on concept {}: {}".format(word, sys.exc_info()[0]) else: return 1 return 1 print (is_good_word('dog')) #Does NOT throw error 

Si tengo una statement de impresión en el mismo archivo en el ámbito global, no se produce el error. Sin embargo, si lo llamo desde mi hilo, lo hace. El siguiente es un ejemplo mínimo para reproducir el error. Lo he probado y en mi máquina da la salida.

 Attribute error on concept dog: 'WordNetCorpusReader' object has no attribute '_LazyCorpusLoader__args' Attribute error on concept dog: 'WordNetCorpusReader' object has no attribute '_LazyCorpusLoader__args' Attribute error on concept dog: 'WordNetCorpusReader' object has no attribute '_LazyCorpusLoader__args' Attribute error on concept dog: 'WordNetCorpusReader' object has no attribute '_LazyCorpusLoader__args' Attribute error on concept dog: 'WordNetCorpusReader' object has no attribute '_LazyCorpusLoader__args' Attribute error on concept dog: 'WordNetCorpusReader' object has no attribute '_LazyCorpusLoader__args' Attribute error on concept dog: 'WordNetCorpusReader' object has no attribute '_LazyCorpusLoader__args' Attribute error on concept dog: 'WordNetCorpusReader' object has no attribute '_LazyCorpusLoader__args' Attribute error on concept dog: 'WordNetCorpusReader' object has no attribute '_LazyCorpusLoader__args' 

Ejemplo mínimo:

 import time import threading from filter_tag import is_good_word class ProcessMetaThread(threading.Thread): def __init__(self): threading.Thread.__init__(self) def run(self): is_good_word('dog') #Throws error def process_meta(numberOfThreads): threadsList = [] for i in range(numberOfThreads): t = ProcessMetaThread() t.setDaemon(True) t.start() threadsList.append(t) numComplete = 0 while numComplete < numberOfThreads: # Iterate over the active processes for processNum in range(0, numberOfThreads): # If a process actually exists if threadsList != None: # If the process is finished if not threadsList[processNum] == None: if not threadsList[processNum].is_alive(): numComplete += 1 threadsList[processNum] = None time.sleep(5) print 'Processes Finished' if __name__ == '__main__': process_meta(10) 

He ejecutado tu código y recibo el mismo error. Para una solución de trabajo, ver más abajo. Aquí está la explicación:

LazyCorpusLoader es un objeto proxy que representa un objeto corpus antes de que se cargue el corpus. (Esto evita que el NLTK cargue corpus masivos en la memoria antes de que los necesite). Sin embargo, la primera vez que se accede a este objeto proxy, se convierte en el corpus que pretende cargar. Es decir, el objeto proxy LazyCorpusLoader transforma su __dict__ y __class__ en el __dict__ y __class__ del corpus que está cargando.

Si compara su código con sus errores anteriores, puede ver que recibió 9 errores cuando intentó crear 10 instancias de su clase. La primera transformación del objeto proxy LazyCorpusLoader en un objeto WordNetCorpusReader fue exitosa. Esta acción se activó cuando accedió a wordnet por primera vez:

El primer hilo

 from nltk.corpus import wordnet as wn def is_good_word(word): ... wn.ensure_loaded() # `LazyCorpusLoader` conversion into `WordNetCorpusReader` starts 

El segundo hilo

Sin embargo, cuando comienza a ejecutar su función is_good_word en un segundo hilo, su primer hilo no ha transformado completamente el objeto proxy LazyCorpusLoader en un WordNetCorpusReader . wn sigue siendo un objeto proxy LazyCorpusLoader , por lo que comienza el proceso de __load nuevamente. Sin embargo, una vez que llega al punto en el que intenta convertir su __class__ y __dict__ en un objeto WordNetCorpusReader , el primer hilo ya ha convertido el objeto proxy LazyCorpusLoader en un WordNetCorpusReader . Mi conjetura es que te encuentras con un error en la línea con mi comentario a continuación:

 class LazyCorpusLoader(object): ... def __load(self): ... corpus = self.__reader_cls(root, *self.__args, **self.__kwargs) # load corpus ... # self.__args == self._LazyCorpusLoader__args args, kwargs = self.__args, self.__kwargs # most likely the line throwing the error 

Una vez que el primer hilo ha transformado el objeto proxy LazyCorpusLoader en un objeto WordNetCorpusReader , los nombres mutilados ya no funcionarán. El objeto WordNetCorpusReader no tendrá LazyCorpusLoader en ninguna parte en sus nombres destrozados. ( self.__args es equivalente a self._LazyCorpusLoader__args mientras que el objeto es un objeto LazyCorpusLoader .) Por lo tanto, LazyCorpusLoader el siguiente error:

 AttributeError: 'WordNetCorpusReader' object has no attribute '_LazyCorpusLoader__args' 

Una alternativa

A la luz de este problema, deseará acceder al objeto wn antes de ingresar a su subproceso. Aquí está su código modificado apropiadamente:

 from nltk.corpus import wordnet as wn from nltk.corpus import stopwords from nltk.corpus.reader.wordnet import WordNetError import sys import time import threading cachedStopWords = stopwords.words("english") def is_good_word(word): word = word.strip() if len(word) <= 2: return 0 if word in cachedStopWords: return 0 try: if len(wn.lemmas(str(word), lang='en')) == 0: # no longer the first access of wn return 0 except WordNetError as e: print("WordNetError on concept {}".format(word)) except AttributeError as e: print("Attribute error on concept {}: {}".format(word, e.message)) except: print("Unexpected error on concept {}: {}".format(word, sys.exc_info()[0])) else: return 1 return 1 class ProcessMetaThread(threading.Thread): def __init__(self): threading.Thread.__init__(self) def run(self): is_good_word('dog') def process_meta(numberOfThreads): print wn.__class__ #  wn.ensure_loaded() # first access to wn transforms it print wn.__class__ #  threadsList = [] for i in range(numberOfThreads): start = time.clock() t = ProcessMetaThread() print time.clock() - start t.setDaemon(True) t.start() threadsList.append(t) numComplete = 0 while numComplete < numberOfThreads: # Iterate over the active processes for processNum in range(0, numberOfThreads): # If a process actually exists if threadsList != None: # If the process is finished if not threadsList[processNum] == None: if not threadsList[processNum].is_alive(): numComplete += 1 threadsList[processNum] = None time.sleep(5) print('Processes Finished') if __name__ == '__main__': process_meta(10) 

He probado el código anterior y no he recibido errores.