Python中子进程中的列表索引超出范围

Posted

技术标签:

【中文标题】Python中子进程中的列表索引超出范围【英文标题】:List index out of range in subprocess in Python 【发布时间】:2014-05-19 19:23:22 【问题描述】:

我正在使用来自this 答案的代码来调高和调低某些程序(在本例中为 BS.player)的音量,但在调用 get_master_volume 函数时我遇到了问题。我在 pyHook 的“OnKeyboardEvent”中使用它,下面是那部分代码:

def get_master_volume():
    config.read('%s/config.cfg'%os.path.abspath(os.path.dirname(__file__)))
    proc = subprocess.Popen('%s sget Master '%config.get('main', input1), shell=True,    stdout=subprocess.PIPE) #config.get gives FULL and correct path to bsplayer.exe
    amixer_stdout = proc.communicate()[0].split('\n')[4]
    proc.wait()

    find_start = amixer_stdout.find('[') + 1
    find_end = amixer_stdout.find('%]', find_start)

    return float(amixer_stdout[find_start:find_end])

def set_master_volume(volume):
    config.read('%s/config.cfg'%os.path.abspath(os.path.dirname(__file__)))
    val = float(int(volume))

    proc = subprocess.Popen('%s sset Master '%config.get('main', input1) + str(val) +  '%', shell=True, stdout=subprocess.PIPE) #config.get gives FULL and correct path to bsplayer.exe
    proc.wait()

def OnKeyboardEvent(event):
    #nothing important
    if config.has_option('main', input1):
       set_master_volume(get_master_volume() - 1)
       print "New volume:", get_master_volume()

这是错误:

File "c:/Users/Amar/Documents/volume+/main.py", line 53, in get_master_volume
     amixer_stdout = proc.communicate()[0].split('\n')[4]
IndexError: list index out of range

谁能解释我为什么会触发此错误以及导致它的原因(以及我应该如何修复它)?

最好的问候!

编辑:

当我打印出 proc.communicate() 时出现此错误,这是什么意思?

proc.communicate:'C:\Program' is not recognized as an internal or external comma
nd,
operable program or batch file.
('', None)

编辑 2:

在我修复了指向错误 bsplayer.exe 路径的配置错误后出现新错误:

 Traceback (most recent call last):
 File "c:\Python27\lib\site-packages\pyHook\HookManager.py", line 351, in Keybo
 ardSwitch
 return func(event)
 File "c:/Users/Amar/Documents/volume+/main.py", line 101, in OnKeyboardEvent
  set_master_volume(get_master_volume() - 1)
 File "c:/Users/Amar/Documents/volume+/main.py", line 54, in get_master_volume
  amixer_stdout = proc.communicate()[0].split('\n')[4]
 File "c:\Python27\lib\subprocess.py", line 798, in communicate
  stdout = _eintr_retry_call(self.stdout.read)
 File "c:\Python27\lib\subprocess.py", line 478, in _eintr_retry_call
  return func(*args)
 ValueError: I/O operation on closed file

【问题讨论】:

要么从proc.communicate() 返回的列表为空,要么从第一个索引中拆分字符串得到的列表没有五个元素。你可能想分割那条线,看看哪一部分中断了。 您的换行符可能比您预期的要少。省略[4] 索引并更改设计以更优雅地处理此问题(包括在意外情况下引发更具体的异常)。 @BrianCain 我在尝试打印 proc.communicate() 时编辑了错误的帖子.. @thegrinner 与上述相同的消息... 你能贴出你用来打印proc.communicate()的行吗? 【参考方案1】:

uuuuh……我刚刚看了你正在使用的另一个问题,但有些东西你完全错过了。您正在尝试将发送到 linux 程序 amixer 的参数与您的 windows 程序 bsplayer.exe 一起使用,这与前者没有任何关系。 非常不太可能奏效!这就是它不起作用的原因。参考另一个问题:

proc = subprocess.Popen('/usr/bin/amixer sget Master', shell=True, stdout=subprocess.PIPE)

所以问题的第一部分是解决你在调用bsplayer.exe 时遇到的问题,但你真正想要它做的事情不起作用。


您应该尝试以下方法来调用子进程:

proc = subprocess.Popen([config.get('main', input1), 'sget', 'Master'], stdout=subprocess.PIPE)

因为,虽然我对 windows 的 python 没有太多经验,但我认为使用 shell 调用它可能无法按预期工作,请尝试将您的路径解释为参数。虽然也许如果你在论点周围加上引号,它可能会起作用:

proc = subprocess.Popen('"%s" sget Master '%config.get('main', input1), shell=True,    stdout=subprocess.PIPE)

让我得出这个结论的原因是:

'C:\Program' is not recognized as an internal or external command,

通常意味着bsplayer.exe的路径在第一个空格处被剪切。


编辑:

您能否运行以下命令并将输出添加到您的问题中?

基本上:

我在交流之前移动了proc.wait() 在第二步中移动了第四行输出的选择 添加了输出列表的打印输出

我想知道您遇到的错误是因为communicate() 无法正常工作,还是因为输出中的行数少于四行。

所以下面的版本解决了你的调用问题:

def get_master_volume():
    config.read('%s/config.cfg'%os.path.abspath(os.path.dirname(__file__)))
    p = [config.get('main', input1), 'sget', 'Master']
    print("PROG:", p)
    proc = subprocess.Popen(p, stdout=subprocess.PIPE)

    proc.wait()

    amixer_stdout = proc.communicate()[0].split('\n')
    print("OUTPUT", amixer_stdout)
    amixer_stdout = amixer_stdout[4]

    find_start = amixer_stdout.find('[') + 1
    find_end = amixer_stdout.find('%]', find_start)

    return float(amixer_stdout[find_start:find_end])

虽然它什么也没输出。

你的命令真的有效吗?!你真的尝试过吗:

"C:\Program Files (x86)\Webteh\BSPlayer\bsplayer.exe" sget Master

在cmd中看看是否有效?

【讨论】:

这是编辑代码的错误:ipaste.eu/view?id=6697Pastebin 不工作所以我把它放在这里,看起来每个 cloudflare 服务器都受到严重的 DDoSed 攻击 第一个:pastebin.com/6VgHntTh 第二个:pastebin.com/6BJcKNfY btw。谢谢你帮我解决这个问题! :) 你太棒了! 代码有错别字,能否重新运行第二个? 嗯,如果我输入它什么都不会返回...看起来这是个问题哈哈...pokit.org/get/img/c5b3ff57e9dd8e3cfb86f50a21d42178.jpg【参考方案2】:

让我试着回答你的这三个(实际上)问题。

    IndexError

    File "c:/Users/Amar/Documents/volume+/main.py", line 53, in get_master_volume
        amixer_stdout = proc.communicate()[0].split('\n')[4]
    IndexError: list index out of range
    

    这意味着[0] 访问尝试访问空序列(不太可能),或者[4] 尝试访问最多包含 4 个条目的序列,因此[4] 不存在。

    显然,输出少于 4 行,因此 proc.communicate()[0].split('\n') 没有 [4] 条目。

    要么程序输出不符合预期,要么有其他问题。

    proc.communicate

    proc.communicate:'C:\Program' is not recognized as an internal or external comma
    

    nd,可运行的程序或批处理文件。 ('', 无)

    这似乎表明您调用的命令行有问题。

    config.get('main', input1) 似乎包含完整路径,它位于C:\Program Files。所以你应该用"(在正确的级别)正确地包围你的程序路径。

    关闭文件上的 I/O

    这第三个问题可以通过检查调用跟踪来解决。这里我们可以看到调用方式有问题:communicate()调用失败,因为子进程的stdout已经关闭了。

    我不清楚为什么会这样;也许你打电话给communicate() 两次?在第一次调用时,它是关闭的,当您尝试第二次调用时,它会失败,因为 stdout 已经被读出。

【讨论】:

以上是关于Python中子进程中的列表索引超出范围的主要内容,如果未能解决你的问题,请参考以下文章

k元组排序中的python列表索引超出范围

Python - 索引错误 - 列表索引超出范围

Python:IndexError:列表索引超出范围

在后台删除的数据导致 UITableView 中的索引超出范围崩溃

IndexError:列表索引超出范围 - python 错误

Python循环:列表索引超出范围