Исключение TypeError предупреждение иногда показано, иногда нет при использовании метода throw генератора
есть такой код:
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)
запуск этого кода:
$ 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
вещь, которую я не понимаю, почему иногда печатается это Exception TypeError
предупреждение. Что-то не так с пользовательским исключением?
3 ответов
вы видите __del__
крюк плохо себя ведет где-то.
на TypeError
вызывается при закрытие, поскольку интерпретатор Python выходит, все удаляется и любые исключения бросаются в __del__
крюк деконструктора игнорируется (но are печать).
при выходе Python очищает все в пространстве имен, восстанавливая все до None
, но порядок, в котором это происходит, не установлено. Еще работающий генератор закрыт (a.close()
вызывается) при удалении, что вызывает GeneratorExit
исключение в генераторе, который Python тестирует против вашего except MyException:
линии. Если, однако, MyException
и уже был очищен и Python видит except None:
на TypeError
бросили и вы видите, что сообщение напечатано.
вы можете вызвать ошибку, не выходя из Python, добавив:
MyException = None
del a
если вы используете list(a)
и потребляют остальную часть генератора или явно закройте генератор с помощью a.close()
перед выходом Python и удалением MyException
, сообщение об ошибке исчезнет.
другой обходной путь был бы обрабатывать GeneratorExit
первый:
def gen():
for i in range(3):
try:
yield i
except GeneratorExit:
return
except MyException:
print("MyException!")
и Python не будет оценивать следующий except
обработчик.
ошибка не может быть воспроизведена с Python 3.2 или ранее, поэтому она выглядит как хэш рандомизации (введено в Python 3.3) рандомизирует объекты порядка очищаются; это, безусловно, объясняет, почему вы смотрите ошибку только на некоторые ваших запусков, но не на более ранних запусках Python, где хэш-порядок фиксирован.
обратите внимание, что взаимодействие .__del__()
крючки и другие глобальные объекты в Python документируются с большим красным предупреждением в .__del__()
документация:
предупреждение: из-за опасных обстоятельств, при которых методы, исключения, возникающие во время их выполнения игнорируется, и предупреждение печатается в
sys.stderr
вместо. Кроме того, когда__del__()
вызывается в ответ на удаляемый модуль (например, при выполнении программы), другие глобалы, на которые ссылается__del__()
метод, возможно, уже был удален или находится в процессе сноса (например, завершение работы импортного оборудования). По этой причине,__del__()
методы должны делать абсолютный минимум, необходимый для поддержания внешних инвариантов. Начиная с версии 1.5, Python гарантирует, что globals имя, начинающееся с одного подчеркивания, удаляется из модуля до удаления других глобалов; если других ссылок на такие глобалы не существует, это может помочь в обеспечении доступности импортированных модулей в то время, когда__del__()
метод называется.
у меня была такая же ошибка в Python 3.3 В Windows, с той разницей, что я определял исключение в своем собственном файле. Это были мои файлы кода:
$ cat FooError.py
class FooError(Exception):
pass
$ cat application.py
import FooError
try:
raise FooError('Foo not bar!')
Except FooError as e:
print(e)
Это было исключение, которое я получаю:
TypeError: перехват классов, которые не наследуются от BaseException, не допускается.
изменение import FooError
to from FooError import *
решен вопрос. Вот окончательный код, для ясности саке:
$ cat FooError.py
class FooError(Exception):
pass
$ cat application.py
from FooError import *
try:
raise FooError('Foo not bar!')
Except FooError as e:
print(e)
У меня была та же проблема, но мне не хватало импорта в класс исключений. Таким образом, интерпретатор не разрешил класс в предложении except.
поэтому просто добавьте импорт и, надеюсь, все будет работать.