Я думаю, что смысл в отношении try...except...else
заключается в том, что легко использовать его для создания несогласованного состояния, а не для его исправления. Это не значит, что этого следует избегать любой ценой, но это может привести к обратным результатам.
Рассмотрим:
try:
file = open('somefile','r')
except IOError:
logger.error("File not found!")
else:
# Some file operations
file.close()
# Some code that no longer explicitly references 'file'
Было бы очень приятно сказать, что приведенный выше блок препятствовал тому, чтобы код пытался получить доступ к файлу, который не существует, или каталогу, для которого у пользователя нет разрешений, и чтобы сказать, что все инкапсулировано, потому что оно находится внутри try...except...else
блок. Но на самом деле большая часть кода в приведенной выше форме действительно должна выглядеть так:
try:
file = open('somefile','r')
except IOError:
logger.error("File not found!")
return False
# Some file operations
file.close()
# Some code that no longer explicitly references 'file'
Вы часто дурачите себя, говоря, что, поскольку на file
больше нет ссылок в области видимости, можно продолжать кодирование после блока, но во многих случаях что-то происходит, когда это просто не в порядке. Или, возможно, позже будет создана переменная в блоке else
, который не создан в блоке except
.
Так я бы отличил if...else
от try...except...else
. В обоих случаях нужно сделать блоки параллельными в большинстве случаев (переменные и набор состояний в одном должны быть установлены в другом), но в последнем случае кодеры часто этого не делают, скорее всего потому, что это невозможно или не имеет значения. В таких случаях часто гораздо важнее возвращаться к вызывающему абоненту, чем пытаться продолжать работать над тем, что, по вашему мнению, будет в лучшем случае.