【发布时间】:2009-02-17 21:20:24
【问题描述】:
是否可以检测 Python 脚本是从命令提示符启动还是通过用户“双击”Windows 文件资源管理器中的 .py 文件启动的?
【问题讨论】:
是否可以检测 Python 脚本是从命令提示符启动还是通过用户“双击”Windows 文件资源管理器中的 .py 文件启动的?
【问题讨论】:
如果从命令行运行,则定义了一个额外的环境变量“PROMPT”。
如果从资源管理器单击此脚本将暂停,如果从命令行运行则不会暂停:
import os
print 'Hello, world!'
if not 'PROMPT' in os.environ:
raw_input()
使用 Python 2.7 在 Windows 7 上测试
【讨论】:
PROMPT 和TCL_LIBRARY。启动 1) python shell, 2) 双击 .py 文件 3) windows cmd: i.stack.imgur.com/CbFUT.jpg
这里是一个如何获取当前运行脚本的父进程id和名称的例子。正如Tomalak 所建议的那样,这可用于检测脚本是从命令提示符启动还是通过在资源管理器中双击启动。
import win32pdh
import os
def getPIDInfo():
"""
Return a dictionary with keys the PID of all running processes.
The values are dictionaries with the following key-value pairs:
- name: <Name of the process PID>
- parent_id: <PID of this process parent>
"""
# get the names and occurences of all running process names
items, instances = win32pdh.EnumObjectItems(None, None, 'Process', win32pdh.PERF_DETAIL_WIZARD)
instance_dict = {}
for instance in instances:
instance_dict[instance] = instance_dict.get(instance, 0) + 1
# define the info to obtain
counter_items = ['ID Process', 'Creating Process ID']
# output dict
pid_dict = {}
# loop over each program (multiple instances might be running)
for instance, max_instances in instance_dict.items():
for inum in xrange(max_instances):
# define the counters for the query
hq = win32pdh.OpenQuery()
hcs = {}
for item in counter_items:
path = win32pdh.MakeCounterPath((None,'Process',instance, None,inum,item))
hcs[item] = win32pdh.AddCounter(hq,path)
win32pdh.CollectQueryData(hq)
# store the values in a temporary dict
hc_dict = {}
for item, hc in hcs.items():
type,val=win32pdh.GetFormattedCounterValue(hc,win32pdh.PDH_FMT_LONG)
hc_dict[item] = val
win32pdh.RemoveCounter(hc)
win32pdh.CloseQuery(hq)
# obtain the pid and ppid of the current instance
# and store it in the output dict
pid, ppid = (hc_dict[item] for item in counter_items)
pid_dict[pid] = {'name': instance, 'parent_id': ppid}
return pid_dict
def getParentInfo(pid):
"""
Returns a PID, Name tuple of the parent process for the argument pid process.
"""
pid_info = getPIDInfo()
ppid = pid_info[pid]['parent_id']
return ppid, pid_info[ppid]['name']
if __name__ == "__main__":
"""
Print the current PID and information of the parent process.
"""
pid = os.getpid()
ppid, ppname = getParentInfo(pid)
print "This PID: %s. Parent PID: %s, Parent process name: %s" % (pid, ppid, ppname)
dummy = raw_input()
当从命令提示符运行时,输出:
此 PID:148。父 PID:4660,父进程名称:cmd
当在资源管理器中双击启动时,输出:
此 PID:1896。父 PID:3788,父进程名称:资源管理器
【讨论】:
命令提示符启动的脚本有一个名为cmd.exe 的父进程(或不存在的进程,以防控制台同时关闭)。
双击启动的脚本应该有一个名为explorer.exe的父进程。
【讨论】:
好问题。您可以做的一件事是在 Windows 中创建脚本的快捷方式,并传递参数(使用快捷方式的 Target 属性),表明脚本是通过双击启动的(在本例中为快捷方式)。
【讨论】:
我将这个小函数 (pybyebye()) 放在我的一些程序中的 return 语句之前。我已经在我的台式机和笔记本电脑上的 Windows 10 下对其进行了测试,它可以满足我的需求,即只有在文件资源管理器中双击程序启动程序时,它才会暂停等待用户输入。这可以防止临时命令窗口在用户说之前消失。在 Linux 下,它什么也不做。反正没坏处!在 Mac 上也是如此。
## PYBYEBYE :
def pybyebye (eprompt="PROMPT",efps="FPS_BROWSER_"):
"nice exit in Windows according to program launch from: IDLE, command, clix."
## first examine environment (os & sys having been imported) :
ui = None
platform = sys.platform
## print("os =",platform)
if not platform.lower().startswith("win"):
return ui ## only relevant in windows
fromidle = False
launched = "Launched from"
if sys.executable.endswith("pythonw.exe"):
fromidle = True ## launched from within IDLE
envkeys = sorted(os.environ)
prompter = eprompt in envkeys
browser = False
for ek in envkeys:
## print(ek)
if ek.startswith(efps):
browser = True
break
## next decide on launch context :
if fromidle and not prompter: ## surely IDLE
## print(launched,"IDLE")
pass ## screen won't disappear
elif browser and not prompter: ## run with double click
## print(launched,"File Explorer")
print("Press Enter to finish ....") ; ui=input()
elif prompter and not fromidle: ## run from preexisting command window
## print(launched,"Command Window")
pass ## screen won't disappear
else: ## something funny going on, Mac or Linux ??
print("launch mode undetermined!")
return ui
【讨论】: