"OSError:告诉下一个()调用禁用位置"的含义"错误?

ber*_*sch 6 python file python-3.x

这几乎与如何解决"OSError:告诉下一个()调用禁用位置"的问题相同.虽然较旧的问题已经收到了一些有用的解决方法的答案,但错误的含义并不清楚.我想知道是否有人可以对此发表评论.

我正在学习Python并且松散地遵循教程.我在Fedora 23上以交互方式输入以下内容:

$ python3
Python 3.4.3 (default, Aug  9 2016, 15:36:17)
[GCC 5.3.1 20160406 (Red Hat 5.3.1-6)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> with open("myfile","r") as file:
...     for l in file:
...         print("Next line: \"{}\"".format(l))
...         print("Current position {:4d}".format(file.tell()))
Run Code Online (Sandbox Code Playgroud)

myfile包含几行文字.输出:

Next line: "This is line number 0
"
Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
OSError: telling position disabled by next() call
Run Code Online (Sandbox Code Playgroud)

谷歌搜索此错误会产生惊人的6个结果.在Windows 10上的Cygwin上使用Python 3.6.4也是如此.

编辑:

tell()文本文件的方法记录如下:

将当前流位置返回为不透明数字.该数字通常不代表底层二进制存储中的多个字节.

"不透明数字"似乎表明我不能只打印它.所以,我替换了第二个print()电话pos = file.tell().结果相同.

use*_*ica 12

该消息意味着它所说的内容:因为您已经调用next()了该文件,tell()因此已禁用该文件的使用.

它看起来可能不像你所调用的那样next,但for循环会隐式调用它.一个for循环:

for element in thing:
    do_stuff_with(element)
Run Code Online (Sandbox Code Playgroud)

是语法糖

iterator = iter(thing) # the real implementation doesn't use a variable
while True:
    try:
        element = next(iterator) # here's the next() call
    except StopIteration:
        break
    do_stuff_with(element)
Run Code Online (Sandbox Code Playgroud)

对于文件,iter(file)返回文件,并对文件进行循环调用next.


至于为什么调用next禁用tell(),这是为了提高效率.它仅发生于文本文件(特别io.TextIOWrapper),这不得不做了一大堆额外的工作来支持tell; 关闭tell支持让他们跳过这项工作.用于进行禁用的更改的原始提交消息是"通过禁用快照更新来加速next().",表明它是为了提高效率.nexttell

对于历史上下文,以前的Python版本使用了隐藏缓冲区next,tell而其他文件方法没有考虑到,导致tell(和其他文件方法)在迭代文件期间产生非常有意义的结果.当前的IO实现将能够tell()在迭代期间提供支持,但io.TextIOWrapper无论如何都会阻止此类调用.next和其他方法之间的历史不兼容可能导致为什么在迭代期间禁用部分文件功能被认为是合理的.


您没有要求解决方法,但为了最终在此页面上寻找解决方法的人们的利益,我会提到

for line in iter(file.readline, ''):
    ...
Run Code Online (Sandbox Code Playgroud)

将允许您迭代文件的行而不禁用tell.(您可以使用for line in iter(file.readline, b'')二进制文件,但没有太大意义,因为tell禁用机制不适用于二进制文件.)

  • @martineau:没有显式的`next`调用,但是`for`隐式地调用`next`。至于其余的答案,这在很大程度上是推测性的,但是已记录了旧的“下一个” /其他方法的不兼容性,并且禁用了告诉功能时,实现*正在*跳过工作。 (2认同)