October 28, 2012

Зачем в python with

Долгое время при работе с файлами из python я писал примерно следующий код:

Без подсветки синтаксиса
def some_func(fname):
    fd = open(fname)
    some_data_processing(fd.read())
    return result

Тут предполагается, что в любом случае при выходе из функции переменная fd уничтожится и вместе с ней закроется файл и все будут жить долго и счастливо.

Но что будет если в some_data_processing произойдет исключение?

Например так:

Без подсветки синтаксиса
import sys

class TestClass(object):
    def __del__(self):
        print "I'm deleted"

def data_process():
    obj = TestClass()
    raise IndexError()

try:
    data_process()
except:
    print "In exception handler"

print "after except"

На консоли появляется:

    In exception handler
    after except
    I'm deleted

Почему-то "In exception handler" и "after except" выводятся раньше "I'm deleted".

Первая проблема в том, что вместе с исключением питон хранит и трейс стека, содержащий все фреймы вплоть до породившего исключение. А внутри фрейма живет f_locals - словарь локальных переменных, и именно он имеет ссылку на экземпляр класса TestClass. Таким образом до окончания обработки исключения obj будет жить точно. Почему же "after except" появляется раньше чем "I'm deleted"? Было бы логично чистить трейс после успешного выхода из блока try. Дело в том что 2.X питон не всегда чистит внутренние структуры после обработки исключения и в общем случае вы должны явно вызывать функцию sys.exc_clear чтобы очистить их. Когда я подошел с этим вопросом к Larry Hastings (одному из основных разработчиков ядра питона) ему потребовалось около 20ти минут, что-бы понять что происходит и найти в документации sys.exc_clear. (Правда стоит отметить, что он давно использует 3.X, где это поведение стало адекватнее.) В 3.X это поведение улучшили, и теперь sys.exc_clear автоматически вызывается окончанию обработки исключения.

Кстати, если вы напишете примерно такой код:

Без подсветки синтаксиса
try:
    data_process()
except:
    fr = sys.exc_info()[2]
    del fr

то не забудьте удалить fr используя del, как в последней строке - иначе он образует циклическую ссылку с текущим фреймом и тогда все станет совсем плохо.

Стоит отметить, что подобное поведение проявляется не всегда. Например следующий код исполняется более предсказуемо:

Без подсветки синтаксиса
import sys

class TestClass(object):
    def __del__(self):
        print "I'm deleted"

def data_process():
    fd = TestClass()
    try:
        raise IndexError()
    except:
        print "In internal exception handler"

data_process()
print "after except"
    In internal exception handler
    I'm deleted
    after except

В общем что-бы гарантированно избавить себя от этих проблем нужно явно закрывать все файлы и прочие объекты или так:

Без подсветки синтаксиса
fd = open(fname)
try:
    process_code()
finally:
    fd.close()

или так:

Без подсветки синтаксиса
with open(fname) as fd:
    process_code()

собственное with именно для этого и был сделан. Без его использования вы рискуете исчерпать лимит на дескрипторы или что-там-еще в зависимости от объектов. Впрочем это только начало печальной истории, продолжение дальше.

Ссылки:
          docs.python.org/2/library/sys.html#sys.exc_clear
          nuitka.net

Исходники этого и других постов со скриптами лежат тут - github.com/koder-ua. При использовании их, пожалуйста, ссылайтесь на koder-ua.blogspot.com.

15 comments:

Goran said...

Хм... попробовал под Ubuntu 12.10 (там как раз оба Python 2.x и 3.x из коробки) - результат один и тот же

igor@ubuntu:~/Dev/PythonResearch$ python except.py
In internal exception handler
I'm deleted
after except
igor@ubuntu:~/Dev/PythonResearch$ python3 except.py
In internal exception handler
I'm deleted
after except

версия 2.x Python 2.7.3 - либо очень произвольно зависит от сборщика мусора (от его выполнения), либо в самой последней версии 2.7.3 пофиксили до нормального поведения :) Вообще интересный момент

Unknown said...

В случае если исключение отлавливается внутри функциимне не удалось воспроизвести это поведение.
В случае же, если исключение отлавливается на уровне модуля(первый пример) - востпроизводится на 100% на 2.7

nivatha said...

Nice post. By reading your blog, i get inspired and this provides some useful information. Thank you for posting this exclusive post for our vision. 
Data Science training in marathahalli
Data Science training in btm
Data Science training in rajaji nagar
Data Science training in chennai
Data Science training in kalyan nagar
Data Science training in electronic city
Data Science training in USA
Data science training in pune

Mounika said...

This is a nice article here with some useful tips for those who are not used-to comment that frequently. Thanks for this helpful information I agree with all points you have given to us. I will follow all of them.
python training in pune
python online training
python training in OMR

shethal said...

Good Post! Thank you so much for sharing this pretty post, it was so good to read and useful to improve my knowledge as updated one, keep blogging.
Devops training in tambaram
DevOps online Training
DevOps Training in USA

ummayasri said...

This is such a great post, and was thinking much the same myself. Another great update.
Blue Prism Training Course in Pune

Blue Prism Training Institute in Bangalore

MOUNIKA said...

Thanks for the informative article. This is one of the best resources I have found in quite some time. Nicely written and great info. I really cannot thank you enough for sharing.
Splunk Training From India

Dellboomi Training From India

pragyachitra said...

Nice tutorial. Thanks for sharing the valuable information. it’s really helpful. Who want to learn this blog most helpful. Keep sharing on updated tutorials…


angularjs Training in chennai
angularjs-Training in pune

angularjs-Training in chennai

angularjs Training in chennai

angularjs-Training in tambaram

Riya Raj said...

Really great blog... Thanks for your information
Selenium Training in Bangalore
Selenium Training in Coimbatore
Selenium Course in Bangalore
selenium course in coimbatore
Java Training in Bangalore
Python Training in Bangalore
IELTS Coaching in Madurai
IELTS Coaching in Coimbatore

Java Training in Coimbatore

easylearn said...

Hi,
Best article, very useful and well explanation. Your post is extremely incredible.Good job & thank you very much for the new information, i learned something new. Very well written. It was sooo good to read and usefull to improve knowledge. Who want to learn this information most helpful. One who wanted to learn this technology IT employees will always suggest you take Python Training Institutes In Btm.

Padminiprwatech said...

Thanks a lot for giving great kind of information. So useful and practical for me. Excellent blog and very informative, nice work keep updating. If you are looking for any Python Programming language related information, check our Python training institute in bangalore web page. Thanks a lot.

raju said...

nice post...!
dominican republic web hosting
iran hosting
palestinian territory web hosting
panama web hosting
syria hosting
services hosting
afghanistan shared web hosting
andorra web hosting
belarus web hosting

shri said...

very good...
internship report on python
free internship in chennai for ece students
free internship for bca
internship for computer science engineering students in india
internships in hyderabad for cse students 2018
electrical companies in hyderabad for internship
internships in chennai for cse students 2019
internships for ece students
inplant training in tcs chennai
internship at chennai

karthickannan said...

nice...
coronavirus update
inplant training in chennai
inplant training
inplant training in chennai for cse
inplant training in chennai for ece
inplant training in chennai for eee
inplant training in chennai for mechanical
internship in chennai
online internship

divya said...

Wow it is really wonderful and awesome thus it is very much useful for me to understand many concepts and helped me a lot. it is really explainable very well and i got more information from your blog.thank you si much.
Ai & Artificial Intelligence Course in Chennai
PHP Training in Chennai
Ethical Hacking Course in Chennai Blue Prism Training in Chennai
UiPath Training in Chennai