AttributeError:StringIO实例没有属性'fileno'

kam*_*mal 18 python

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 
Run Code Online (Sandbox Code Playgroud)

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

AttributeError: StringIO instance has no attribute 'fileno'

为什么我会收到此错误,如何更正错误?

sam*_*ias 13

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

- fileno() is left unimplemented so that code which uses it 
triggers an exception early.
Run Code Online (Sandbox Code Playgroud)

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

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

from StringIO import StringIO
sys.stdout = StringIO()
captureOutput(testfunc)
Run Code Online (Sandbox Code Playgroud)

错误:

    oldstdout = os.dup(sys.stdout.fileno())
AttributeError: StringIO instance has no attribute 'fileno'
Run Code Online (Sandbox Code Playgroud)

最好从头到尾跟踪代码,寻找sys.stdout被覆盖的点.这是我给出的另一个答案链接,显示了如何通过跟踪活动来执行代码:

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


Boa*_*niv 5

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

有时您可以通过写入将stdout重置为默认标准输出sys.stdout = sys.__stdout__,但不要指望它始终有效.例如,它在Pythonwin中不起作用.

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

sys.stdout = os.fdopen(outfd, 'w')
sys.stderr = os.fdopen(errfd, 'w')
Run Code Online (Sandbox Code Playgroud)

编辑:

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

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
Run Code Online (Sandbox Code Playgroud)