You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Python中subprocess.Popen执行报错求助(新手入门问题)

问题:Python subprocess.Popen报错:TypeError: 'NoneType' object is not iterable(办公启动脚本)

我是Python新手,刚完成一门YouTube上的Python入门课程,目前正在将办公用的启动批处理文件转为Python脚本作为首个项目。该脚本原本需要打开我办公时所需的所有应用程序,但编写的代码运行时出现报错。

我的代码如下:

import subprocess
keys = []
open_now = ""
count = 0
programs_to_run = {'Chrome': r'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe', 'Outlook': r'C:\Program Files\Microsoft Office\\root\Office16\OUTLOOK.exe'}
# 将字典中的键存入可用列表
for key in programs_to_run.keys():
    # print(key)
    keys.append(key)
for program in programs_to_run:
    open_now = "programs_to_run.get(programs_to_run.get(keys[count]))"
    subprocess.Popen(open_now)
    print(f'Opening {keys[count]}!')
    # print(programs_to_run.get(keys[count]))
    count += 1
print("*****************************************************************")
print("All applications opened fine.")
print("*****************************************************************")
input('Press ENTER to exit')
quit()

我曾在命令提示符中测试subprocess.Popen('完整路径'),运行正常,单独打印相关代码段也没问题,但运行上述完整代码时出现如下报错:

Traceback (most recent call last):
File "C:/Users/User/OneDrive - Company/Python_Projects/WorkSetup/WorkSetup.py", line 28, in <module>
subprocess.Popen(programs_to_run.get(programs_to_run.get(keys[count])))
File "C:\Users\User\AppData\Local\Programs\Python\Python38-32\lib\subprocess.py", line 854, in __init__
self._execute_child(args, executable, preexec_fn, close_fds,
File "C:\Users\User\AppData\Local\Programs\Python\Python38-32\lib\subprocess.py", line 1247, in _execute_child
args = list2cmdline(args)
File "C:\Users\User\AppData\Local\Programs\Python\Python38-32\lib\subprocess.py", line 549, in list2cmdline
for arg in map(os.fsdecode, seq):
TypeError: 'NoneType' object is not iterable

希望能得到入门级的帮助,我的最终目标是让该脚本/可执行文件随电脑启动,判断是否处于办公环境(本地域可达),若是则打开全部应用,否则仅打开2个应用(目前暂未实现该判断功能)。


解答

先说说报错的核心原因

你这段代码里绕了个没必要的弯,还犯了两个小错误:

  1. 你把programs_to_run.get(...)写成了字符串赋值给open_now,就算去掉引号,programs_to_run.get(programs_to_run.get(keys[count]))也是错的——programs_to_run.get(keys[count])已经是程序的路径了,再拿这个路径当key去字典里找值,自然找不到,返回None,而subprocess.Popen接收到None就会报这个迭代错误。
  2. 手动维护keys列表和count变量完全没必要,遍历字典有更简单的方式。

修正后的代码

import subprocess

# 修正了Office路径的双斜杠(r前缀已经转义,单斜杠就够)
programs_to_run = {
    'Chrome': r'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe',
    'Outlook': r'C:\Program Files\Microsoft Office\root\Office16\OUTLOOK.exe'
}

# 直接遍历字典的键值对,不用额外维护列表和计数器
for app_name, app_path in programs_to_run.items():
    try:
        # 用列表形式传路径是subprocess的最佳实践,避免路径含空格的问题
        subprocess.Popen([app_path])
        print(f'Opening {app_name}!')
    except Exception as e:
        # 捕获异常,就算某个程序启动失败也不影响其他程序
        print(f'Failed to open {app_name}: {str(e)}')

print("*****************************************************************")
print("All applications opened (or attempted to open) fine.")
print("*****************************************************************")
input('Press ENTER to exit')

代码细节解释

  1. 更简洁的字典遍历:用programs_to_run.items()可以直接拿到每个程序的名称和路径,省去手动存keys和计数的麻烦,代码更清晰不易出错。
  2. subprocess的正确用法:把路径放在列表里[app_path]是官方推荐的写法,能避免路径里有空格时的解析问题,比直接传字符串更稳妥。
  3. 异常捕获:增加try-except块后,就算某个程序路径写错或者权限不足,脚本也能继续启动其他程序,还能告诉你具体哪里出了问题。
  4. 路径修正:把Office路径里的\\改成\,因为r开头的原始字符串中,单个\就代表路径分隔符,双斜杠会变成实际的两个斜杠,可能导致路径找不到。

后续域判断功能的入门思路

要判断是否在办公域,最入门的方法可以试试ping域服务器或者访问内网共享,这里给你一个ping的示例:

import subprocess

def is_in_work_domain():
    # 替换成你的域服务器IP或内网主机名
    domain_server = "your-domain-server.local"
    # Windows下ping命令用-n指定次数,Linux/macOS用-c
    result = subprocess.run(
        ["ping", "-n", "1", domain_server],
        capture_output=True,
        text=True,
        # 隐藏命令窗口(Windows下生效)
        creationflags=subprocess.CREATE_NO_WINDOW
    )
    # 返回码为0说明ping通了,代表在办公域
    return result.returncode == 0

# 使用示例
if is_in_work_domain():
    print("检测到办公环境,启动全部程序")
    # 这里放启动所有程序的代码
else:
    print("不在办公环境,启动常用程序")
    # 这里放启动2个指定程序的代码

把这段逻辑和之前的启动代码结合,就能实现你的最终需求啦。

内容的提问来源于stack exchange,提问作者DragonStar445

火山引擎 最新活动