python Python子进程“对象没有属性'fileno'”错误

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/777996/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 20:50:45  来源:igfitidea点击:

Python subprocess "object has no attribute 'fileno'" error

pythonpipesubprocess

提问by epochwolf

This code generates "AttributeError: 'Popen' object has no attribute 'fileno'" when run with Python 2.5.1

使用 Python 2.5.1 运行时,此代码生成“AttributeError: 'Popen' object has no attribute 'fileno'”

Code:

代码:

def get_blame(filename): 
    proc = []
    proc.append(Popen(['svn', 'blame', shellquote(filename)], stdout=PIPE))
    proc.append(Popen(['tr', '-s', r"'0'"], stdin=proc[-1]), stdout=PIPE)
    proc.append(Popen(['tr', r"'0'", r"';'"], stdin=proc[-1]), stdout=PIPE)
    proc.append(Popen(['cut', r"-d", r"\;", '-f', '3'], stdin=proc[-1]), stdout=PIPE)
    return proc[-1].stdout.read()

Stack:

堆:

function walk_folder in blame.py at line 55
print_file(os.path.join(os.getcwd(), filename), path)

function print_file in blame.py at line 34
users = get_blame(filename)

function get_blame in blame.py at line 20
proc.append(Popen(['tr', '-s', r"'0'"], stdin=proc[-1]), stdout=PIPE)

function __init__ in subprocess.py at line 533
(p2cread, p2cwrite,

function _get_handles in subprocess.py at line 830
p2cread = stdin.fileno()

This code should be working the python docs describe this usage.

这段代码应该可以工作,python 文档描述了这种用法

回答by S.Lott

Three things

三件事

First, your ()'s are wrong.

首先,你的 () 是错误的。

Second, the result of subprocess.Popen()is a process object, not a file.

其次,结果subprocess.Popen()是一个进程对象,而不是一个文件。

proc = []
proc.append(Popen(['svn', 'blame', shellquote(filename)], stdout=PIPE))
proc.append(Popen(['tr', '-s', r"'0'"], stdin=proc[-1]), stdout=PIPE)

The value of proc[-1]isn't the file, it's the process that contains the file.

的值proc[-1]不是文件,而是包含文件的进程。

proc.append(Popen(['tr', '-s', r"'0'"], stdin=proc[-1].stdout, stdout=PIPE))

Third, don't do all that trand cutjunk in the shell, few things could be slower. Write the trand cutprocessing in Python -- it's faster and simpler.

第三,不要在 shell 中做所有这些trcut垃圾,很少有事情会变慢。用 Python编写trcut处理——它更快更简单。

回答by dbr

There's a few weird things in the script,

剧本里有一些奇怪的东西,

  • Why are you storing each process in a list? Wouldn't it be much more readable to simply use variables? Removing all the .append()sreveals an syntax error, several times you have passed stdout=PIPE to the appendarguments, instead of Popen:

    proc.append(Popen(...), stdout=PIPE)
    

    So a straight-rewrite (still with errors I'll mention in a second) would become..

    def get_blame(filename): 
        blame = Popen(['svn', 'blame', shellquote(filename)], stdout=PIPE)
        tr1 = Popen(['tr', '-s', r"'0'"], stdin=blame, stdout=PIPE)
        tr2 = Popen(['tr', r"'0'", r"';'"], stdin=tr1), stdout=PIPE)
        cut = Popen(['cut', r"-d", r"\;", '-f', '3'], stdin=tr2, stdout=PIPE)
        return cut.stdout.read()
    
  • On each subsequent command, you have passed the Popen object, notthat processes stdout. From the "Replacing shell pipeline"section of the subprocess docs, you do..

    p1 = Popen(["dmesg"], stdout=PIPE)
    p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
    

    ..whereas you were doing the equivalent of stdin=p1.

    The tr1 =(in the above rewritten code) line would become..

    tr1 = Popen(['tr', '-s', r"'0'"], stdin=blame.stdout, stdout=PIPE)
    
  • You do not need to escape commands/arguments with subprocess, as subprocess does not run the command in any shell (unless you specify shell=True). See the Securitysection of the subprocess docs.

    Instead of..

    proc.append(Popen(['svn', 'blame', shellquote(filename)], stdout=PIPE))
    

    ..you can safely do..

    Popen(['svn', 'blame', filename], stdout=PIPE)
    
  • As S.Lott suggested, don't use subprocess to do text-manipulations easier done in Python (the tr/cut commands). For one, tr/cut etc aren't hugely portable (different versions have different arguments), also they are quite hard to read (I've no idea what the tr's and cut are doing)

    If I were to rewrite the command, I would probably do something like..

    def get_blame(filename): 
        blame = Popen(['svn', 'blame', filename], stdout=PIPE)
        output = blame.communicate()[0] # preferred to blame.stdout.read()
        # process commands output:
        ret = []
        for line in output.split("\n"):
            split_line = line.strip().split(" ")
            if len(split_line) > 2:
                rev = split_line[0]
                author = split_line[1]
                line = " ".join(split_line[2:])
    
                ret.append({'rev':rev, 'author':author, 'line':line})
    
        return ret
    
  • 为什么要将每个进程存储在列表中?简单地使用变量不是更易读吗?删除所有.append()s显示语法错误,多次将 stdout=PIPE 传递给append参数,而不是 Popen:

    proc.append(Popen(...), stdout=PIPE)
    

    因此,直接重写(仍然有错误,我将在稍后提及)将成为..

    def get_blame(filename): 
        blame = Popen(['svn', 'blame', shellquote(filename)], stdout=PIPE)
        tr1 = Popen(['tr', '-s', r"'0'"], stdin=blame, stdout=PIPE)
        tr2 = Popen(['tr', r"'0'", r"';'"], stdin=tr1), stdout=PIPE)
        cut = Popen(['cut', r"-d", r"\;", '-f', '3'], stdin=tr2, stdout=PIPE)
        return cut.stdout.read()
    
  • 在每个后续命令中,您都传递了 Popen 对象,而不是processes stdout。从子流程文档的“替换外壳管道”部分,您可以...

    p1 = Popen(["dmesg"], stdout=PIPE)
    p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
    

    ..而你正在做相当于stdin=p1.

    tr1 =(在上面的重写代码)线将成为..

    tr1 = Popen(['tr', '-s', r"'0'"], stdin=blame.stdout, stdout=PIPE)
    
  • 您不需要使用 subprocess 转义命令/参数,因为 subprocess 不会在任何 shell 中运行命令(除非您指定shell=True)。请参阅子流程文档的安全部分。

    代替..

    proc.append(Popen(['svn', 'blame', shellquote(filename)], stdout=PIPE))
    

    ..你可以安全地做..

    Popen(['svn', 'blame', filename], stdout=PIPE)
    
  • 正如 S.Lott 所建议的那样,不要使用 subprocess 来执行在 Python 中更容易完成的文本操作(tr/cut 命令)。一方面,tr/cut 等不是非常便携(不同版本有不同的参数),它们也很难阅读(我不知道 tr 和 cut 在做什么)

    如果我要重写命令,我可能会做类似的事情..

    def get_blame(filename): 
        blame = Popen(['svn', 'blame', filename], stdout=PIPE)
        output = blame.communicate()[0] # preferred to blame.stdout.read()
        # process commands output:
        ret = []
        for line in output.split("\n"):
            split_line = line.strip().split(" ")
            if len(split_line) > 2:
                rev = split_line[0]
                author = split_line[1]
                line = " ".join(split_line[2:])
    
                ret.append({'rev':rev, 'author':author, 'line':line})
    
        return ret
    

回答by Jason Coon

You want the stdout of the process, so replace your stdin=proc[-1]with stdin=proc[-1].stdout

你想要过程的标准输出,所以stdin=proc[-1]stdin=proc[-1].stdout

Also, you need to move your paren, it should come after the stdoutargument.

另外,你需要移动你的括号,它应该在stdout论点之后。

 proc.append(Popen(['tr', '-s', r"'0'"], stdin=proc[-1]), stdout=PIPE)

should be:

应该:

 proc.append(Popen(['tr', '-s', r"'0'"], stdin=proc[-1].stdout, stdout=PIPE))

Fix your other appendcalls in the same way.

append以相同的方式修复您的其他呼叫。

回答by SilentGhost

looks like syntax error. except first append the rest are erroneous (review brackets).

看起来像语法错误。除了先追加,其余都是错误的(复习括号)。

回答by orip

Like S.Lott said, processing the text in Python is better.

就像 S.Lott 所说,用 Python 处理文本更好。

But if you want to use the cmdline utilities, you can keep it readable by using shell=True:

但是如果你想使用 cmdline 实用程序,你可以使用shell=True以下命令保持它的可读性:

cmdline = r"svn blame %s | tr -s '0' | tr '0' ';' | cut -d \; -f 3" % shellquote(filename)
return Popen(cmdline, shell=True, stdout=PIPE).communicate()[0]