python with

在你打开一个文件的时候,你也许会这样写:

myfile = open('data.txt')
data = myfile.read()
print(data)

这段代码有一个问题就是读取文件可能出错,并且没有关闭文件,那么我们修改代码如下:

myfile = open('data.txt')

try:
    data = myfile.read()
    print(data)
finally:
    myfile.close()

这段代码可以正常运行(其实如果文件不存在也会抛错,我们关注点不在此),有的时候你也可能忘记关闭文件,或者每次都要写try finally,比较麻烦。那么,就是使用with的时候了。

with open('data.txt') as myfile:
    data = myfile.read()
    print(data)
使用with就不用每次都写try finally了,而且文件也会正常关闭,那么文件为什么会关闭呢,我们看下面的例子:

class Myfile:
    def __enter__(self):
        print('enter execute')
        return 'object returned by enter'
    def __exit__(self, type, value, trace):
        print('exit execute')

def myopen():
    return Myfile()

with myopen() as myfile:
    print("result: " + myfile)
这段代码输出结果如下:

enter execute
result: object returned by enter
exit execute

我们看到with statment 首先执行了myfile的enter方法,并且将enter返回值赋值给了as后边的变量myfile,最后with语句块执行完成后调用了myfile的exit方法。


我们再看另外一个例子:

class Myfile:  
    def __enter__(self):  
        print('enter execute')  
        return 'object returned by enter'  
    def __exit__(self, type, value, trace):  
        print('exit execute')  
        print("value:", value)

def myopen():  
    return Myfile()  
  
with myopen() as myfile:    
    print("result: " + myfile)
    print(1/0)
输入结果如下:

enter execute
result: object returned by enter
exit execute
('value:', ZeroDivisionError('integer division or modulo by zero',))
Traceback (most recent call last):
  File "D:\06workspace\eclipse\python\demo\with.py", line 24, in <module>
    print(1/0)
ZeroDivisionError: integer division or modulo by zero

可以看到在with语句块中,抛出一个异常,我们同时也看到打印了exit execute,也就是说Myfile的exit方法执行了,并且在exit里获取到了异常信息。也就是说不管什么情况

with语句返回对象的exit方法都会被执行。


其实,我们可以看python里fileobject的定义:

static PyMethodDef file_methods[] = {
    {"readline",  (PyCFunction)file_readline, METH_VARARGS, readline_doc},
    {"read",      (PyCFunction)file_read,     METH_VARARGS, read_doc},
    {"write",     (PyCFunction)file_write,    METH_VARARGS, write_doc},
    {"fileno",    (PyCFunction)file_fileno,   METH_NOARGS,  fileno_doc},
    {"seek",      (PyCFunction)file_seek,     METH_VARARGS, seek_doc},
#ifdef HAVE_FTRUNCATE
    {"truncate",  (PyCFunction)file_truncate, METH_VARARGS, truncate_doc},
#endif
    {"tell",      (PyCFunction)file_tell,     METH_NOARGS,  tell_doc},
    {"readinto",  (PyCFunction)file_readinto, METH_VARARGS, readinto_doc},
    {"readlines", (PyCFunction)file_readlines, METH_VARARGS, readlines_doc},
    {"xreadlines",(PyCFunction)file_xreadlines, METH_NOARGS, xreadlines_doc},
    {"writelines",(PyCFunction)file_writelines, METH_O,     writelines_doc},
    {"flush",     (PyCFunction)file_flush,    METH_NOARGS,  flush_doc},
    {"close",     (PyCFunction)file_close,    METH_NOARGS,  close_doc},
    {"isatty",    (PyCFunction)file_isatty,   METH_NOARGS,  isatty_doc},
    {"__enter__", (PyCFunction)file_self,     METH_NOARGS,  enter_doc},
    {"__exit__",  (PyCFunction)file_exit,     METH_VARARGS, exit_doc},
    {NULL,            NULL}             /* sentinel */
};

file对象定义了enter 和exit方法,也就是读取文件之后,我们可以在exit里做点什么,看下面:

static PyObject *
file_exit(PyObject *f, PyObject *args)
{
    PyObject *ret = PyObject_CallMethod(f, "close", NULL);
    if (!ret)
        /* If error occurred, pass through */
        return NULL;
    Py_DECREF(ret);
    /* We cannot return the result of close since a true
     * value will be interpreted as "yes, swallow the
     * exception if one was raised inside the with block". */
    Py_RETURN_NONE;
}
在文件对象的exit方法里进行了关闭,所以我们在使用with打开一个文件之后,不需要关心文件没有关闭的情况了,因为文件对象定义了enter和exit方法。我们在开发的时候,清理资源,关闭文件等等操作,都可以放在__exit__方法当中。








  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值