异常TypeError警告有时显示,有时不使用发生器的throw方法 [英] Exception TypeError warning sometimes shown, sometimes not when using throw method of generator

查看:1314
本文介绍了异常TypeError警告有时显示,有时不使用发生器的throw方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有以下代码:

  class MyException(Exception):
pass

def gen():
for i in range(3):
try:
yield i
除了MyException:
print(MyException!)


a = gen()
next(a)
a.throw(MyException)

运行此代码:

  $ python3.3 main.py 
MyException!
$ python3.3 main.py
MyException!
异常TypeError:类型错误(catch不允许从BaseException继承的类不允许',)在<生成器对象gen中0xb712efa4>忽略
$ python3.3 main.py
MyException!
$ python3.3 main.py
MyException!
$ python3.3 main.py
MyException!
异常TypeError:在0xb714afa4的< generator对象gen中,TypeError('捕获不能从BaseException继承的类不允许',)忽略

我不明白的是为什么有时打印这个异常TypeError 警告。自定义异常有什么问题吗?

解决方案

你看到一个 __ del __

关闭时, TypeError 正在抛出,因为Python解释器正在退出,所有内容都被删除,并且在 __ del __ 解构函数钩子中抛出的任何异常都被忽略(但是打印)。退出时,Python通过将所有内容重新绑定到而清除命名空间中的所有内容,但发生这种情况的顺序没有设置当被删除时,仍然运行的生成器被关闭( a.close()),这会触发 GeneratorExit exception该生成器,Python测试您的除了MyException:行。但是,如果 MyException 已经被清除,并且Python看到除了None: TypeError 被抛出,您会看到打印的消息。



您可以通过添加: / p>

  MyException =无
del a

如果您使用 list(a)并消耗生成器的其余部分,或者使用 a.close()在Python退出并删除 MyException 之前,错误消息消失。



另一个解决办法是首先处理 GeneratorExit

  def gen():
for i in range(3):
try:
yield i
除了GeneratorExit:
return
除了MyException:
print(MyException!)

,Python不会评估下一个除了处理程序。



e rror不能用Python 3.2或更早版本复制,所以它看起来像哈希随机化(在Python 3.3中引入)随机化清除订单对象;这肯定解释了为什么你只看到你的运行的一些错误,但不是早期的Python运行中的哈希顺序是固定的。



请注意,在 .__ del __()文档


警告:由于 __ del __()方法的不稳定情况被调用时,在执行期间发生的异常将被忽略,并且将警告打印到 sys.stderr 。另外,当 __ del __()被响应于被删除的模块时被调用(例如,当执行程序完成时),由 __ del __()方法可能已被删除或正在被拆除(例如进口机器关闭)。因此, __ del __()方法应该保持外部不变量的绝对最小值。从版本1.5开始,Python保证在其他全局变量被删除之前,其名称以单个下划线开头的全局变量从其模块中删除;如果没有其他引用这样的全局变量存在,这可能有助于确保导入的模块在调用 __ del __()方法时仍然可用。



There is this code:

class MyException(Exception):
  pass

def gen():
  for i in range(3):
    try:
      yield i
    except MyException:
      print("MyException!")


a = gen()
next(a) 
a.throw(MyException)

Running this code:

$ python3.3 main.py
MyException!
$ python3.3 main.py
MyException!
Exception TypeError: TypeError('catching classes that do not inherit from BaseException is not allowed',) in <generator object gen at 0xb712efa4> ignored
$ python3.3 main.py
MyException!
$ python3.3 main.py
MyException!
$ python3.3 main.py
MyException!
Exception TypeError: TypeError('catching classes that do not inherit from BaseException is not allowed',) in <generator object gen at 0xb714afa4> ignored

The thing which I don't understand is why sometimes there is printed this Exception TypeError warning. Is there something wrong with custom exception?

解决方案

You are seeing a __del__ hook misbehaving somewhere.

The TypeError is being thrown while shutting down, as the Python interpreter is exiting everything is deleted and any exceptions thrown in a __del__ deconstructor hook are being ignored (but are printed).

On exit, Python clears everything in the namespace by rebinding everything to None, but the order in which this happens is not set. The still running generator is closed (a.close() is called) when deleted, which triggers a GeneratorExit exception in the generator, which Python tests against your except MyException: line. If, however, MyException has already been cleared up and Python sees except None: the TypeError is thrown and you see that message printed.

You can trigger the error without exiting Python by adding:

MyException = None
del a

If you use list(a) and consume the rest of the generator, or explicitly close the generator with a.close() before Python exits and deletes MyException, the error message goes away.

Another work-around would be to handle GeneratorExit first:

def gen():
  for i in range(3):
    try:
      yield i
    except GeneratorExit:
      return
    except MyException:
      print("MyException!")

and Python will not evaluate the next except handler.

The error cannot be reproduced with Python 3.2 or earlier, so it looks like hash randomization (introduced in Python 3.3) randomizes the order objects are cleared; this certainly explains why you see the error only on some of your runs, but not on earlier Python runs where the hash order is fixed.

Note that the interaction of .__del__() hooks and other global objects in Python is documented with a big red warning in the .__del__() documentation:

Warning: Due to the precarious circumstances under which __del__() methods are invoked, exceptions that occur during their execution are ignored, and a warning is printed to sys.stderr instead. Also, when __del__() is invoked in response to a module being deleted (e.g., when execution of the program is done), other globals referenced by the __del__() method may already have been deleted or in the process of being torn down (e.g. the import machinery shutting down). For this reason, __del__() methods should do the absolute minimum needed to maintain external invariants. Starting with version 1.5, Python guarantees that globals whose name begins with a single underscore are deleted from their module before other globals are deleted; if no other references to such globals exist, this may help in assuring that imported modules are still available at the time when the __del__() method is called.

这篇关于异常TypeError警告有时显示,有时不使用发生器的throw方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆