Python子进程中列表索引超出范围
我在使用来自这个回答的代码来调节某个程序(在这个例子中是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
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
这个错误意味着你在尝试访问一个空的序列(这种情况不太可能),或者你在用
[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
这似乎表明你的命令行调用有问题。
config.get('main', input1)
似乎包含了完整的路径,而这个路径在C:\Program Files
下。所以你应该在正确的位置用"
把程序路径包起来。I/O on closed file
第三个问题可以通过检查调用的记录来解决。在这里我们可以看到调用的方式有问题:
communicate()
的调用失败,因为子进程的stdout
已经关闭了。我不太清楚为什么会这样;也许你是调用了
communicate()
两次?第一次调用时,它已经关闭了,而当你尝试第二次调用时,就失败了,因为stdout
已经被读取完了。
呃……我刚刚看了你提到的另一个问题,发现你完全忽略了一点。你试图把发给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])
不过它什么也不输出。
你的命令真的有效吗?!你有没有尝试在cmd中运行:
"C:\Program Files (x86)\Webteh\BSPlayer\bsplayer.exe" sget Master
看看它是否能工作?