Недавно меня укусило нечто неожиданное. Я хотел сделать что-то подобное:
try :
thing.merge(iterable) # this is an iterable so I add it to the list
except TypeError :
thing.append(iterable) # this is not iterable, so I add it
Что ж, он работал нормально, пока я не передал объект, унаследованный от Exception, который должен был быть добавлен.
К сожалению, исключение можно повторять. Следующий код не вызывает TypeError:
for x in Exception() :
print 1
Кто-нибудь знает почему?






НЕДЕЙСТВИТЕЛЬНО. Проверь Брайана Анусера.
Хорошо, я только что понял:
for x in Exception("test") :
print x
....:
....:
test
Не беспокойтесь ;-)
В любом случае, это хорошо знать.
Обновлено: глядя на комментарии, я чувствую, что хочу добавить некоторые пояснения.
Исключение содержит сообщение, которое вы передали во время создания экземпляра:
raise Exception("test")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
Exception: test
Справедливо сказать, что сообщение - это то, что лучше всего определяет исключение, поэтому str () возвращает его:
print Exception("test")
test
Теперь случается, что исключения неявно преобразуются в строку, когда они используются не в контексте исключения.
Итак, когда я это сделаю:
for x in Exception("test") :
print x
Я повторяю строку «test».
И когда я это сделаю:
for x in Exception() :
print x
Я перебираю пустую строку. Сложный. Потому что, когда дело касается моей проблемы:
try :
thing.merge(ExceptionLikeObject)
except TypeError :
...
Это ничего не вызовет, поскольку ExceptionLikeObject рассматривается как строка.
Итак, мы знаем КАК, но я все еще не понимаю, ПОЧЕМУ. Может быть, встроенное исключение наследуется от встроенного String? Потому что, насколько я знаю:
Больше не проблема, но все еще загадка.
Обратите внимание, что происходящее не связано ни с каким неявным преобразованием строк и т. д., А потому, что класс Exception реализует ___getitem__ для возврата значений из кортежа args (ex.args). Вы можете видеть это по тому факту, что вы получаете всю строку как свой первый и единственный элемент в итерации, а не посимвольный результат, который вы получили бы, если перебираете строку.
Это меня тоже удивило, но, подумав об этом, я предполагаю, что это из соображений обратной совместимости. В Python, использовавшемся для (до 1.5), отсутствует текущая иерархия классов исключений. Вместо этого были выброшены строки с (обычно) аргументом кортежа для любых деталей, которые должны быть переданы в блок обработки, то есть:
try:
raise "something failed", (42, "some other details")
except "something failed", args:
errCode, msg = args
print "something failed. error code %d: %s" % (errCode, msg)
Похоже, это поведение было введено, чтобы избежать нарушения кода до 1.5, ожидающего кортеж аргументов, а не не повторяемый объект исключения. Есть несколько примеров этого с IOError в разделе Fatal Breakage выше связь.
Строковые исключения уже давно устарели и исчезли в Python 3. Объекты исключений больше не повторяются в Python 3:
>>> list(Exception("test"))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'Exception' object is not iterable
Блестяще! Спасибо за объяснение. Я хотел бы принять ответ, но, похоже, нам нужно еще немного проголосовать, прежде чем мне будет позволено.
Ссылки неработающие. Вы можете их обновить?
На самом деле он обрабатывает его не как строку, а как кортеж аргументов. т.е. list (Exception ("test")) == ["test"], а не ["t", "e", "s", "t"]. Аналогично list (Exception (1,2)) == [1, 2]. См. Мой ответ ниже, чтобы понять, почему это может быть.