如果您使用的是 Python 2,则细节会有点模糊;alexmcf 的回答 https://stackoverflow.com/a/30792730/908494涵盖了基础知识,您可以从那里查找更多详细信息。
如果您使用的是 Python 3,所有内容都详细记录在io https://docs.python.org/3/library/io.html模块,并带有一个合理可读的纯Python实现 https://hg.python.org/cpython/file/defauly/Lib/_pyio.py在 stdlib 中,所有这些都构建在一个非常简单的“原始文件”接口之上(FileIO
在 Unix 上的 POSIX 本机文件描述符之上实现)。
The IOBase https://docs.python.org/3/library/io.html#i-o-base-classesABC/mixin 提供了__iter__
方法基于readline
method:
IOBase
(及其子类)支持迭代器协议,这意味着IOBase
可以迭代对象来生成流中的行。根据流是二进制流(产生字节)还是文本流(产生字符串),行的定义略有不同。看readline()
below.
如果你看3.5 源码里面 https://hg.python.org/cpython/file/3.5/Lib/_pyio.py#l516,就像您期望的那样简单:
def __iter__(self):
self._checkClosed()
return self
def __next__(self):
line = self.readline()
if not line:
raise StopIteration
return line
当然,在 CPython 3.1+ 中,如果可能的话,可以使用 C 加速器来代替 Python 代码,但是它看起来很相似 https://hg.python.org/cpython/file/3.5/Modules/_io/iobase.c#l609:
static PyObject *
iobase_iter(PyObject *self)
{
if (_PyIOBase_check_closed(self, Py_True) == NULL)
return NULL;
Py_INCREF(self);
return self;
}
static PyObject *
iobase_iternext(PyObject *self)
{
PyObject *line = PyObject_CallMethodObjArgs(self, _PyIO_str_readline, NULL);
if (line == NULL)
return NULL;
if (PyObject_Size(line) == 0) {
Py_DECREF(line);
return NULL;
}
return line;
}
返回的文件对象open
,并自动创建诸如sys.stdout
,以及在 stdlib 中其他位置创建的大多数或所有文件对象(GzipFile
等),是TextIOWrapper https://docs.python.org/3/library/io.html#io.TextIOWrapper(对于文本文件),或BufferedRandom https://docs.python.org/3/library/io.html#io.BufferedRandom, BufferedReader
, or BufferedWriter
(对于二进制文件),它们都继承了此行为IOBase
。没有什么可以阻止不同的文件类覆盖__iter__
(或注册IOBase
作为 ABC 而不是继承它),但我不知道有任何这样做。