【问题标题】:AttributeError: StringIO instance has no attribute 'fileno'AttributeError:StringIO 实例没有属性“fileno”
【发布时间】:2011-08-19 16:44:23
【问题描述】:
def captureOutput(self, func, *args, **kwargs):
    pass
    sys.stdout.flush()
    sys.stderr.flush()
    (outfd, fn) = tempfile.mkstemp()
    fout = os.fdopen(outfd, 'r')
    os.unlink(fn)
    (errfd, fn) = tempfile.mkstemp()
    ferr = os.fdopen(errfd, 'r')
    os.unlink(fn)
    try:
        oldstdout = os.dup(sys.stdout.fileno())
        oldstderr = os.dup(sys.stderr.fileno())
        os.dup2(outfd, sys.stdout.fileno())
        os.dup2(errfd, sys.stderr.fileno())
        try:
            ret = func(*args, **kwargs)
        finally:
            sys.stderr.flush()
            sys.stdout.flush()
            os.dup2(oldstdout, sys.stdout.fileno())
            os.close(oldstdout)
            os.dup2(oldstderr, sys.stderr.fileno())
            os.close(oldstderr)

        os.lseek(outfd, 0, 0)
        out = fout.read()
        os.lseek(errfd, 0, 0)
        err = ferr.read()
    finally:
        fout.close()
        ferr.close()
    return ret, out, err 

运行此代码时,出现错误:

AttributeError:StringIO 实例没有属性“fileno”

为什么会出现此错误,我该如何纠正?

【问题讨论】:

  • 需要更多代码,outfd和errfd是什么?
  • 你使用的是标准的普通 python 解释器吗?当您使用覆盖 stdout/stderr 的解释器时,可能会出现此错误,例如 IDLE(尽管 IDLE 本身会给您一个不同的错误)。它也可能是由覆盖 stdout/stderr 的库引起的。

标签: python


【解决方案1】:

fileno() 方法未在 StringIO 中实现,因为它不是真实文件(因此没有关联的文件描述符)。来源:

- fileno() is left unimplemented so that code which uses it 
triggers an exception early.

可能有人将 sys.stdout 替换为 StringIO 实例,以捕获输出。

例如,当我以这种方式运行您的代码时,我得到了同样的异常:

from StringIO import StringIO
sys.stdout = StringIO()
captureOutput(testfunc)

错误:

    oldstdout = os.dup(sys.stdout.fileno())
AttributeError: StringIO instance has no attribute 'fileno'

最好从头到尾跟踪您的代码,寻找sys.stdout 被覆盖的点。这是link to another answer I gave,展示了如何在跟踪活动的情况下执行代码:

ares% python -m trace -c -t -C ./coverage test_sio.py | grep sys.stdout
test_sio.py(47): sys.stdout = StringIO()

【讨论】:

  • 我找不到任何导入的 StringIO,可能是使用了 dup() 和 dup2() 吗?那会导致错误吗?现在:dup() 和 dup2() 解释如下:并返回 FileDescriptors。 os.dup(fd) 返回文件描述符 fd 的副本。可用性:Unix、Windows。 os.dup2(fd, fd2) 将文件描述符 fd 复制到 fd2,必要时先关闭后者。可用性:Unix、Windows。
  • @kamal 我不认为dup() 会导致该特定错误。尝试访问缺少的[obj].fileno 属性时会发生异常。您是否在 IDE 下运行?如另一个答案中所述,也许您的 IDE 正在交换 StringIO。
  • 我没有在 IDE 中运行,而是在 shell (bash) 中运行,所以我有一个 bash 脚本使用鼻子测试驱动这些脚本
  • @kamal 试试 Python 追踪器 - 我已经用更多细节更新了我的答案。
  • 这是很好的信息,谢谢,但我相信在这种情况下 test_sio.py 是可执行的(该行是否有 no if name__=='__main' )是否正确?这在我的情况下是不正确的
【解决方案2】:

您使用的是标准的普通 python 解释器吗?当您使用覆盖 stdout/stderr 的解释器时可能会出现此错误,例如 IDLE(尽管 IDLE 本身会给您一个不同的错误)。它也可能是由覆盖 stdout/stderr 的库引起的。

有时您可以通过写sys.stdout = sys.__stdout__ 将您的标准输出重置为默认标准输出,但不要指望它总是能正常工作。例如,它在 Pythonwin 中不起作用。

无论如何,您尝试对代码执行的操作似乎是自己重定向 stdout/stderr。如果是这样的话,你应该继续做。如果您有文件描述符outfderrfd,我认为这应该可行:

sys.stdout = os.fdopen(outfd, 'w')
sys.stderr = os.fdopen(errfd, 'w')

编辑:

现在我可以看到你的整个代码,我根本不会使用临时文件。

def captureOutput(self, func, *args, **kwargs):
    import cStringIO # You can also use StringIO instead

    sys.stderr.flush()
    sys.stdout.flush()
    olderr, oldout = sys.stderr, sys.stdout
    try:
        sys.stderr = cStringIO.StringIO()
        sys.stdout = cStringIO.StringIO()
        try:
            ret = func(*args, **kwargs)
        finally:
            stderr.seek(0)
            stdout.seek(0)            
            err = stderr.read()
            out = stdout.read()
    finally:
        sys.stderr = olderr
        sys.stdout = oldout

    return ret, out, err

【讨论】:

  • 使用 Python 2.7.5... 函数不是 cStringIO.getvalue() 代替 cStringIO.read() 吗?另外,你不应该关闭 cStringIO 实例吗?
【解决方案3】:

简短的回答是您在标准库中遇到了一个错误。 StringIO 不履行其 IOBase 基类的契约。某些类写入 IOBase 类接口,然后失败。

更具体地说,Subprocess.run() 或其他一些函数使用了 IOBase fileno 函数。子类 StringIO 抛出此异常,因为它不是真正的子类。某处,IOBase 的众多用户之一失败了。记录 StringIO 并不能解决这个问题。

也许你可以围绕它编写代码。或者可能不是。诸如 contextlib.redirect_stdout() 之类的各种函数都会失败。

【讨论】:

    【解决方案4】:

    我的猜测是代码中的其他地方,sys.stdout 或 sys.stderr 被重新分配为 StringIO 的一个实例。这段代码在什么环境下运行(比如在一些 web 框架内,从命令行)?这可能会给熟悉该环境的人提供正确答案的线索。

    【讨论】:

      猜你喜欢
      • 2017-06-26
      • 1970-01-01
      • 1970-01-01
      • 2019-07-22
      • 2018-03-17
      • 2016-06-29
      • 2012-10-07
      • 2013-02-27
      • 1970-01-01
      相关资源
      最近更新 更多