为什么此subprocess.check_output行崩溃了我的脚本?

时间:2018-08-06 04:56:59

标签: python split subprocess pyinstaller strsplit

我有一个脚本,在.pyw中时工作正常,但是在转换为.exe时,(编辑:实际上,当我将pyinstaller与参数-w--windowed或{{ 1}}无效,但是如果没有它们,它将起作用)我发现这一行似乎使程序崩溃了:

--noconsole

有人知道为什么吗?如果我将其注释掉,程序不会崩溃。我还有另外两行非常相似。

编辑:

也许将脚本放在这里是个好主意...

firstplan = subprocess.check_output(["powercfg", "-list"], shell=True ).split('\n')[3]

麻烦的行是21-23行。

有关更多信息,请向下滚动至评论和答案。

1 个答案:

答案 0 :(得分:3)

我不确定这是否可以解决您的问题,但这是一个重构,用于解决注释中指出的问题以及代码中的其他一些问题。

  • 不要使用循环变量。 (它还是没被使用。)
  • 不要运行相同的子进程三次。
  • 避免不必要的shell=True
  • 出于一致性和正确性的考虑,优选/list而不是-list

我删除了您的评论,并内联了我的评论,解释了确切的更改。

# Only necessary in Python 2, you really should be using Python 3 now
#from __future__ import print_function
# Only used in os.system('cls') which was commented out (for good reasons I presume)
#import os
import psutil
import subprocess
from time import sleep # see below

# Simply loop forever; break when done
while True:
    # Remove gratuitous parentheses
    CPUload = psutil.cpu_percent(interval=4)
    RAMload = psutil.virtual_memory().percent

    # Use .format() to inline a string
    print("CPU Load: {}%".format(CPUload)))
    print("RAM Load: {}%".format(RAMload))

    # Only run subprocess once; use /list pro -list; don't use shell=True
    pcfg = subprocess.check_output(["powercfg", "/list"], shell=False).split('\n')
    # Additional refactoring below ########
    firstplan = pcfg[3]
    secondplan = pcfg[4]
    thirdplan = pcfg[5]

    # Get rid of wacky parentheses    
    firstplanID = firstplan.split(": ")[1].split("  (")[0]
    secondplanID = secondplan.split(": ")[1].split("  (")[0]
    thirdplanID = thirdplan.split(": ")[1].split("  (")[0]

    activeplan = subprocess.check_output(["powercfg", "/getactivescheme"])
    # Get rid of wacky parentheses
    activeplanNAME = activeplan.split("(")[1].split(")")[0]    
    firstplanNAME = firstplan.split("(")[1].split(")")[0]
    secondplanNAME = secondplan.split("(")[1].split(")")[0]
    thirdplanNAME = thirdplan.split("(")[1].split(")")[0]

    if "High performance" in firstplanNAME:
        HighPerformance = firstplanNAME
        HighPerformanceID = firstplanID

    if "High performance" in secondplanNAME:
        HighPerformance = secondplanNAME
        HighPerformanceID = secondplanID

    if "High performance" in thirdplanNAME:
        HighPerformance = thirdplanNAME
        HighPerformanceID = thirdplanID

    if "Power saver" in firstplanNAME:
        PowerSaver = firstplanNAME
        PowerSaverID = firstplanID

    if "Power saver" in secondplanNAME:
        PowerSaver = secondplanNAME
        PowerSaverID = secondplanID

    if "Power saver" in thirdplanNAME:
        PowerSaver = thirdplanNAME  
        PowerSaverID = thirdplanID

    # Additional refactoring ends    

    if activeplanNAME == PowerSaver:
        print("Active plan: Power saver")
    # prefer if / elif / else over nested if
    elif activeplanNAME == HighPerformance:
        print("Active plan: High Performance")
    else:
        # What's this supposed to do? You are capturing, then discarding the output.
        # Perhaps you are looking for subprocess.check_call()?
        subprocess.check_output(["powercfg", "/s", HighPerformanceID])          

    if CPUload < 44:    
        # Combine conditions rather than nesting conditionals
        if RAMload > 90 and activeplanNAME == PowerSaver:
            # subprocess.check_call() here too?
            subprocess.check_output(["powercfg", "/s", HighPerformanceID])
            print("Switching to High Performance by RAM load...")       

        # Don't check if CPUload < 44: again
        # Instead, just stay within this indented block
        # Combine conditions
        elif RAMload < 90 and activeplanNAME == HighPerformance:
            # subprocess.check_call() here too?
            subprocess.check_output(["powercfg", "/s", PowerSaverID])
            print("Switching to Power saver...")                    

        # What if RAMload == 90?

    # Combine conditions
    if CPUload > 55 and activeplanNAME == PowerSaver:
        # subprocess.check_call() here too?
        subprocess.check_output(["powercfg", "/s", HighPerformanceID])
        print("Switching to High Performance...")

    # Maybe sleep between iterations?
    #sleep(1)

该脚本当前运行相当紧凑的循环,您可能想取消最后一行的注释。

仍然有很多重复的代码。您可能需要考虑进一步的重构,以将三个计划收集到一个数组中,其中每个对象都是字典,成员名称标识您提取的不同属性。

    # Additional refactoring below ########
    activeplan = subprocess.check_output(["powercfg", "/getactivescheme"])
    activeplanNAME = activeplan.split("(")[1].split(")")[0]    

    plan = []
    for idx in range(3):
        raw = pcfg[3+idx]
        thisplan = {'raw': raw}
        thisplan['id'] = raw.split(": ")[1].split("  (")[0]
        thisplan['name'] = raw.split("(")[1].split(")")[0]

        if "High performance" in thisplan['name']:
            HighPerformance = thisplan['name']
            HighPerformanceID = thisplan['id']    

        if "Power saver" in thisplan['name']:
            PowerSaver = thisplan['name']
            PowerSaverID = thisplan['id']

        plan[idx] = thisplan    

现在,您实际上可以更改HighPerformancePowerSaver变量以仅记住idx,然后,如果需要,可以使用{从字典列表中拉出名称。 {1}}和ID plan[PowerSaverIdx]['name']