skr*_*sme 6 python exception python-3.x
我正在观察Python 3.3.4中我希望帮助理解的行为:为什么在正常执行函数时正确引发异常,而不是在函数池中执行函数时?
import multiprocessing
class AllModuleExceptions(Exception):
"""Base class for library exceptions"""
pass
class ModuleException_1(AllModuleExceptions):
def __init__(self, message1):
super(ModuleException_1, self).__init__()
self.e_string = "Message: {}".format(message1)
return
class ModuleException_2(AllModuleExceptions):
def __init__(self, message2):
super(ModuleException_2, self).__init__()
self.e_string = "Message: {}".format(message2)
return
def func_that_raises_exception(arg1, arg2):
result = arg1 + arg2
raise ModuleException_1("Something bad happened")
def func(arg1, arg2):
try:
result = func_that_raises_exception(arg1, arg2)
except ModuleException_1:
raise ModuleException_2("We need to halt main") from None
return result
pool = multiprocessing.Pool(2)
results = pool.starmap(func, [(1,2), (3,4)])
pool.close()
pool.join()
print(results)
Run Code Online (Sandbox Code Playgroud)
此代码产生此错误:
线程中的异常Thread-3:
Traceback(最近一次调用最后一次):
文件"/user/peteoss/encap/Python-3.4.2/lib/python3.4/threading.py",第921行,在_bootstrap_inner
self.run中( )
文件"/user/peteoss/encap/Python-3.4.2/lib/python3.4/threading.py",第869行,运行
self._target(*self._args,**self._kwargs)
文件"/ user/peteoss/encap/Python-3.4.2/lib/python3.4/multiprocessing/pool.py",第420行,在_handle_results
task = get()
文件"/user/peteoss/encap/Python-3.4.2/ lib/python3.4/multiprocessing/connection.py",第251行,在recv中
返回ForkingPickler.loads(buf.getbuffer())TypeError:__ init __()缺少1个必需的位置参数:'message2'
相反,如果我只是调用该函数,它似乎正确处理异常:
print(func(1, 2))
Run Code Online (Sandbox Code Playgroud)
生产:
回溯(最近调用最后一次):
文件"exceptions.py",第40行,
打印(func(1,2))
文件"exceptions.py",第30行,在func中
引发ModuleException_2("我们需要暂停main" )from None
__main __.ModuleException_2
为什么ModuleException_2
在进程池中运行时行为会有所不同?
Blc*_*ght 12
问题是您的异常类在其__init__
方法中具有非可选参数,但是当您调用超类__init__
方法时,您不会传递这些参数.当您的异常实例被multiprocessing
代码取消时,这会导致新的异常.
这是Python异常的一个长期存在的问题,你可以在这个错误报告中阅读相当多的问题历史(其中一部分基本问题与酸洗异常是固定的,但不是你的部分'重击).
总结一下这个问题:Python的基Exception
类将它所__init__
接收的所有参数都放入一个名为的属性中args
.这些参数被放入pickle
数据中,当流被取消时,它们被传递给__init__
新创建的对象的方法.如果接收到的参数数量与Exception.__init__
子类所期望的数量不同,则在unpickling时会出现错误.
该问题的解决方法是将自定义异常类在其__init__
方法中需要的所有参数传递给超类__init__
:
class ModuleException_2(AllModuleExceptions):
def __init__(self, message2):
super(ModuleException_2, self).__init__(message2) # the change is here!
self.e_string = "Message: {}".format(message2)
Run Code Online (Sandbox Code Playgroud)
另一种可能的解决方法是根本不调用超类__init__
方法(这是上面链接的bug中允许的修复),但由于这通常是子类的不良行为,我不能真正推荐它.
归档时间: |
|
查看次数: |
1673 次 |
最近记录: |