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中子进程中的列表索引超出范围的主要内容,如果未能解决你的问题,请参考以下文章
在后台删除的数据导致 UITableView 中的索引超出范围崩溃