Здавалося б, return "from try" мав спрацювати. Але finally виконується завжди - навіть після return. І якщо в ньому є свій return, він перекриває той, що був у try.
Те саме з винятками: return у finally проковтне навіть виняток, який мав вилетіти назовні.
def g():
try:
raise ValueError("boom")
finally:
return "all good"
g() # "all good", виняток зник
Помилка сталася, але про неї ніхто не дізнається. Такий баг ловиться довго, бо код виглядає цілком робочим.
Висновок: finally тримай тільки для очищення (закрити файл, зʼєднання, відпустити лок). Ніяких return чи raise всередині - інакше він тихо перепише всю логіку вище.
У пайтоні прийнято писати if x is None, а не if x == None. І це не просто стиль.
None - це єдиний обʼєкт на всю програму. Скільки б разів ти не написав None, це завжди той самий обʼєкт у памʼяті. Тому is тут найточніша й найшвидша перевірка: порівняння за ідентичністю, без зайвих викликів.
== працює інакше - він викликає метод __eq__. А його можна перевизначити. І тоді == None починає працювати неочікувано:
class Weird:
def __eq__(self, other):
return True
w = Weird()
w == None # True
w is None # False
Обʼєкт очевидно не None, але == каже, що None. З is такого не станеться ніколи бо його не можна перевизначити.
Коротко: для None (як і для True/False) завжди is. Це швидше, надійніше і не залежить від того, що хтось накрутив в __eq__.
У пайтоні є оператор is, який перевіряє не рівність значень, а те, чи це один і той самий обʼєкт у памʼяті. І тут ховається несподіванка:
a = 256
b = 256
a is b # True
a = 257
b = 257
a is b # False
Значення однакові, а результат різний. Причина в тому, що CPython при старті створює й тримає в кеші всі малі цілі від -5 до 256. Вони використовуються постійно, тож інтерпретатор не робить нові обʼєкти щоразу - віддає ті самі.
Число 257 у кеш не потрапляє, тому кожне таке присвоєння - новий обʼєкт. Звідси False.
І ще нюанс: якщо написати 257 is 257 в одному рядку чи в одній функції, компілятор може сам згорнути константи, і вийде True. Тобто поведінка залежить від того, де саме стоїть код.
Висновок простий: is для чисел використовувати не треба взагалі. Він про ідентичність обʼєкта, а не про значення. Для порівняння чисел завжди ==.