'NoneType' 对象没有属性 'earlierDate_'
'NoneType' object has no attribute 'earlierDate_'
我刚刚开始学习 Python,为了做到这一点,我正在努力实现一个简单的聊天机器人。在我想实现一些文本到语音功能之前,它工作得很好,当它们出现在屏幕上时它会说出这些行。
为了实现这一目标,我不得不深入研究多线程,这就是我被困的地方:
import concurrent.futures
import pyttsx3
from time import sleep
import sys
# Settings
engine = pyttsx3.init()
voices = engine.getProperty('voices')
engine.setProperty('voice', voices[0].id)
typing_delay=0.035
def textToSpeech(text):
engine.say(text)
engine.runAndWait()
def typing(sentence):
for char in sentence:
sleep(typing_delay)
sys.stdout.write(char)
sys.stdout.flush()
# def parallel(string):
# tasks = [lambda: textToSpeech(string), lambda: typing("\n> "+string+"\n\n")]
# with ThreadPoolExecutor(max_workers=2) as executor:
# futures = [executor.submit(task) for task in tasks]
# for future in futures:
# try:
# future.result()
# except Exception as e:
# print(e)
def parallel(text):
with concurrent.futures.ThreadPoolExecutor(max_workers=2) as executor:
future_tasks = {executor.submit(textToSpeech, text), executor.submit(typing, "\n> "+text+"\n\n")}
for future in concurrent.futures.as_completed(future_tasks):
try:
data = future.result()
except Exception as e:
print(e)
# Test Sentence
parallel("Greetings Professor Falken")
顶部的两个函数应该运行 并行。我已经为我的 parallel() 函数尝试了两种不同的实现(一个被注释掉了),但是这两种实现都产生了相同的结果。对于聊天机器人发出的第一行文本,我实际上同时收到了文本和语音,但随后出现错误:
'NoneType' object has no attribute 'earlierDate_'
之后,我只收到文字,不再有语音和错误:run loop already started
我假设 concurrent.futures
中的某处是属性 'earlierDate_'
并且我没有正确处理它,因此文本到语音线程永远不会停止。但我不知道如何解决它。
我希望这里有人有可能有所帮助的想法。我已将我的代码缩减到尽可能小但仍然可以 运行 和测试的东西。
附录:我在 Python 3.8 上导入 pyttsx3
时遇到问题,所以我降级到 Python 3.7,它似乎可以工作。
更新:
所以我想到,当我专注于多线程时,问题可能一直出在我的文本转语音实现上。
最明显的一点是我在全局初始化我的语音引擎。所以我将我的设置移到了 textToSpeech 函数中:
def textToSpeech(text):
engine = pyttsx3.init()
voices = engine.getProperty('voices')
engine.setProperty('voice', voices[0].id)
engine.say(text)
engine.runAndWait()
run loop already started
错误现在不会立即出现,我在前几次聊天机器人交互中收到了文本和语音。
我仍然收到 'NoneType' object has no attribute 'earlierDate_'
错误,现在在每个聊天机器人输出之后,最终 run loop already started
错误再次出现,我失去了声音。不过,我想更近了一步。
更新 2:
经过又一天的挖掘,我想我又近了一步。
这似乎是与多线程相关的 Mac 特定问题。我在不同领域发现了多个问题,人们 运行 遇到了这个问题。
我在 PyObjCTools/AppHelper.py
中找到了问题
我们有以下功能:
def runConsoleEventLoop(
argv=None, installInterrupt=False, mode=NSDefaultRunLoopMode, maxTimeout=3.0
):
if argv is None:
argv = sys.argv
if installInterrupt:
installMachInterrupt()
runLoop = NSRunLoop.currentRunLoop()
stopper = PyObjCAppHelperRunLoopStopper.alloc().init()
PyObjCAppHelperRunLoopStopper.addRunLoopStopper_toRunLoop_(stopper, runLoop)
try:
while stopper.shouldRun():
nextfire = runLoop.limitDateForMode_(mode)
if not stopper.shouldRun():
break
soon = NSDate.dateWithTimeIntervalSinceNow_(maxTimeout)
nextfire = nextfire.earlierDate_(soon)
if not runLoop.runMode_beforeDate_(mode, nextfire):
stopper.stop()
finally:
PyObjCAppHelperRunLoopStopper.removeRunLoopStopperFromRunLoop_(runLoop)
靠近按钮的这一行是罪魁祸首:nextfire = nextfire.earlierDate_(soon)
对象 nextfire
似乎是一个日期。在 Objective-C 中,NSDate 对象确实有一个 earlierDate()
方法,所以它应该可以工作。但是初始化有问题。当我 print(nextfire)
时,我得到 None
。那么 NoneType 对象没有属性 'earlierDate_'.
也就不足为奇了
所以,我有点解决了我的两个问题,但是,我以一种不令人满意的方式解决了它们。这有点老套。但这是我能做的最好的,除了剖析 pyttsx3
.
1) 首先,对于 run loop already started
错误的问题:
我已将我的引擎初始化移回 textToSpeech
函数之外的全局级别(就像在我的初始代码片段中一样)。
然后,每次调用 textToSpeech
函数之前,我都会输入以下代码:
try:
engine.endLoop()
except Exception as e:
pass
这样,当已经有一个循环时 运行,它会在新调用之前停止,从而防止错误发生。如果没有循环 运行,什么也不会发生。
2) 我的 'NoneType' object has no attribute 'earlierDate_'
错误的主要问题更加深入。我查看了各种来源,但我并不完全了解那里发生了什么。
正如我在第二次更新中所写,错误源自 PyObjCTools/AppHelper.py
。 nextfire
使用 NSRunLoop
中的 limitDateForMode
方法初始化,根据 Apple 文档 returns nil
如果此模式没有输入源。
下一步是查看 pyttsx3/nsss.py
实例化 PyObjCTools/AppHelper.py
中的方法的位置。但是我并没有真正理解该实例化是如何工作的以及如何解决 NSRunLoop
显然在没有输入源的情况下被实例化的事实,或者是否应该解决这个问题。
所以我进行了一次肮脏的黑客攻击,并通过在 earlierDate_
调用中切换 nextfire
和 soon
来更改 PyObjCTools/AppHelper.py
:
try:
while stopper.shouldRun():
nextfire = runLoop.limitDateForMode_(mode)
if not stopper.shouldRun():
break
soon = NSDate.dateWithTimeIntervalSinceNow_(maxTimeout)
nextfire = soon.earlierDate_(nextfire)
if not runLoop.runMode_beforeDate_(mode, nextfire):
stopper.stop()
finally:
PyObjCAppHelperRunLoopStopper.removeRunLoopStopperFromRunLoop_(runLoop)
soon
变量总是正确地实例化为 NSDate
对象,因此方法 earlierDate
可用。显然它也适用于 nil
作为参数。
当然,如果所涉及的两个库之一中有适当的修复,那就更好了。我的猜测是 pyttsx3/nsss.py
需要一些工作,但我对 NSRunLoops
的了解不够,无法得出明智的意见。
我刚刚开始学习 Python,为了做到这一点,我正在努力实现一个简单的聊天机器人。在我想实现一些文本到语音功能之前,它工作得很好,当它们出现在屏幕上时它会说出这些行。 为了实现这一目标,我不得不深入研究多线程,这就是我被困的地方:
import concurrent.futures
import pyttsx3
from time import sleep
import sys
# Settings
engine = pyttsx3.init()
voices = engine.getProperty('voices')
engine.setProperty('voice', voices[0].id)
typing_delay=0.035
def textToSpeech(text):
engine.say(text)
engine.runAndWait()
def typing(sentence):
for char in sentence:
sleep(typing_delay)
sys.stdout.write(char)
sys.stdout.flush()
# def parallel(string):
# tasks = [lambda: textToSpeech(string), lambda: typing("\n> "+string+"\n\n")]
# with ThreadPoolExecutor(max_workers=2) as executor:
# futures = [executor.submit(task) for task in tasks]
# for future in futures:
# try:
# future.result()
# except Exception as e:
# print(e)
def parallel(text):
with concurrent.futures.ThreadPoolExecutor(max_workers=2) as executor:
future_tasks = {executor.submit(textToSpeech, text), executor.submit(typing, "\n> "+text+"\n\n")}
for future in concurrent.futures.as_completed(future_tasks):
try:
data = future.result()
except Exception as e:
print(e)
# Test Sentence
parallel("Greetings Professor Falken")
顶部的两个函数应该运行 并行。我已经为我的 parallel() 函数尝试了两种不同的实现(一个被注释掉了),但是这两种实现都产生了相同的结果。对于聊天机器人发出的第一行文本,我实际上同时收到了文本和语音,但随后出现错误:
'NoneType' object has no attribute 'earlierDate_'
之后,我只收到文字,不再有语音和错误:run loop already started
我假设 concurrent.futures
中的某处是属性 'earlierDate_'
并且我没有正确处理它,因此文本到语音线程永远不会停止。但我不知道如何解决它。
我希望这里有人有可能有所帮助的想法。我已将我的代码缩减到尽可能小但仍然可以 运行 和测试的东西。
附录:我在 Python 3.8 上导入 pyttsx3
时遇到问题,所以我降级到 Python 3.7,它似乎可以工作。
更新: 所以我想到,当我专注于多线程时,问题可能一直出在我的文本转语音实现上。
最明显的一点是我在全局初始化我的语音引擎。所以我将我的设置移到了 textToSpeech 函数中:
def textToSpeech(text):
engine = pyttsx3.init()
voices = engine.getProperty('voices')
engine.setProperty('voice', voices[0].id)
engine.say(text)
engine.runAndWait()
run loop already started
错误现在不会立即出现,我在前几次聊天机器人交互中收到了文本和语音。
我仍然收到 'NoneType' object has no attribute 'earlierDate_'
错误,现在在每个聊天机器人输出之后,最终 run loop already started
错误再次出现,我失去了声音。不过,我想更近了一步。
更新 2:
经过又一天的挖掘,我想我又近了一步。 这似乎是与多线程相关的 Mac 特定问题。我在不同领域发现了多个问题,人们 运行 遇到了这个问题。
我在 PyObjCTools/AppHelper.py
中找到了问题我们有以下功能:
def runConsoleEventLoop(
argv=None, installInterrupt=False, mode=NSDefaultRunLoopMode, maxTimeout=3.0
):
if argv is None:
argv = sys.argv
if installInterrupt:
installMachInterrupt()
runLoop = NSRunLoop.currentRunLoop()
stopper = PyObjCAppHelperRunLoopStopper.alloc().init()
PyObjCAppHelperRunLoopStopper.addRunLoopStopper_toRunLoop_(stopper, runLoop)
try:
while stopper.shouldRun():
nextfire = runLoop.limitDateForMode_(mode)
if not stopper.shouldRun():
break
soon = NSDate.dateWithTimeIntervalSinceNow_(maxTimeout)
nextfire = nextfire.earlierDate_(soon)
if not runLoop.runMode_beforeDate_(mode, nextfire):
stopper.stop()
finally:
PyObjCAppHelperRunLoopStopper.removeRunLoopStopperFromRunLoop_(runLoop)
靠近按钮的这一行是罪魁祸首:nextfire = nextfire.earlierDate_(soon)
对象 nextfire
似乎是一个日期。在 Objective-C 中,NSDate 对象确实有一个 earlierDate()
方法,所以它应该可以工作。但是初始化有问题。当我 print(nextfire)
时,我得到 None
。那么 NoneType 对象没有属性 'earlierDate_'.
所以,我有点解决了我的两个问题,但是,我以一种不令人满意的方式解决了它们。这有点老套。但这是我能做的最好的,除了剖析 pyttsx3
.
1) 首先,对于 run loop already started
错误的问题:
我已将我的引擎初始化移回 textToSpeech
函数之外的全局级别(就像在我的初始代码片段中一样)。
然后,每次调用 textToSpeech
函数之前,我都会输入以下代码:
try:
engine.endLoop()
except Exception as e:
pass
这样,当已经有一个循环时 运行,它会在新调用之前停止,从而防止错误发生。如果没有循环 运行,什么也不会发生。
2) 我的 'NoneType' object has no attribute 'earlierDate_'
错误的主要问题更加深入。我查看了各种来源,但我并不完全了解那里发生了什么。
正如我在第二次更新中所写,错误源自 PyObjCTools/AppHelper.py
。 nextfire
使用 NSRunLoop
中的 limitDateForMode
方法初始化,根据 Apple 文档 returns nil
如果此模式没有输入源。
下一步是查看 pyttsx3/nsss.py
实例化 PyObjCTools/AppHelper.py
中的方法的位置。但是我并没有真正理解该实例化是如何工作的以及如何解决 NSRunLoop
显然在没有输入源的情况下被实例化的事实,或者是否应该解决这个问题。
所以我进行了一次肮脏的黑客攻击,并通过在 earlierDate_
调用中切换 nextfire
和 soon
来更改 PyObjCTools/AppHelper.py
:
try:
while stopper.shouldRun():
nextfire = runLoop.limitDateForMode_(mode)
if not stopper.shouldRun():
break
soon = NSDate.dateWithTimeIntervalSinceNow_(maxTimeout)
nextfire = soon.earlierDate_(nextfire)
if not runLoop.runMode_beforeDate_(mode, nextfire):
stopper.stop()
finally:
PyObjCAppHelperRunLoopStopper.removeRunLoopStopperFromRunLoop_(runLoop)
soon
变量总是正确地实例化为 NSDate
对象,因此方法 earlierDate
可用。显然它也适用于 nil
作为参数。
当然,如果所涉及的两个库之一中有适当的修复,那就更好了。我的猜测是 pyttsx3/nsss.py
需要一些工作,但我对 NSRunLoops
的了解不够,无法得出明智的意见。