【问题标题】:Detect where Python code is running (e.g., in Spyder interpreter vs. IDLE vs. cmd)检测 Python 代码在哪里运行(例如,在 Spyder 解释器、IDLE 和 cmd 中)
【发布时间】:2013-07-17 16:40:22
【问题描述】:

Python 中是否有一种方法可以在进程中检测该进程的执行位置?我有一些包含getpass.getpass() 函数的代码,其中is broken in Spyder,一直在命令行和IDE 之间来回切换很烦人。如果我可以添加如下代码会很有用:

if not being run from Spyder:
    use getpass
else:
    use alternative

【问题讨论】:

  • sys.executable 对您有帮助吗? docs.python.org/2/library/sys.html#sys.executable
  • @DanLecocq 这很有帮助。我会稍微研究一下,看看我能想出什么。
  • 我试过了,但问题是 Spyder 只是调用了普通的 python 可执行文件。我注意到的一件事是它覆盖了 sys.exit() 调用,这样它就不会杀死你的解释器。有人知道如何利用它吗?

标签: python interpreter spyder


【解决方案1】:

这是我最终使用的解决方案。在阅读了Markus's answer 之后,我注意到 Spyder 在os.environ 中添加了六个左右的环境变量,名称如SPYDER_ENCODINGSPYDER_SHELL_ID 等。与检测这些变量中的任何一个相比,检测这些变量的存在似乎相对明确。缺少与'PYTHONSTARTUP' 一样通用名称的变量。代码很简单,并且独立于 Spyder 的启动脚本(据我所知):

if any('SPYDER' in name for name in os.environ)
    # use alternative
else:        
    # use getpass

由于字符串在每个环境变量名称的开头,你也可以使用str.startswith,但它不太灵活,而且速度有点慢(我很好奇):

>>> import timeit
>>> s = timeit.Timer("[name.startswith('SPYDER') for name in os.environ]", "import os")
>>> i = timeit.Timer("['SPYDER' in name for name in os.environ]", "import os")
>>> s.timeit()
16.18333065883474
>>> i.timeit()
6.156869294143846

sys.executable 方法可能有用也可能没用,具体取决于您的安装。我有几个 WinPython 安装和一个单独的 Python 2.7 安装,因此我能够检查条件 sys.executable.find('WinPy') == -1 以检测 Spyder 使用的可执行文件路径中的文件夹名称。由于当您尝试使用 getpass 时在 IDLE 中显示的警告没有可能的“响亮”,在我看来,我最终还检查了条件 sys.executable.find('pythonw.exe') == -1 以使其稍微响亮。仅使用sys.executable,该方法如下所示:

if sys.executable.find('pythonw.exe') == sys.executable.find('WinPy') == -1:
    # use getpass
else:        
    # use alternative

但是由于我希望它可以在其他机器上运行,并且另一个用户修改他们的 WinPython 安装文件夹名称而不是重命名他们的 IDLE 可执行文件的可能性更大,所以我的最终代码使用sys.executable 来检测 IDLE 和 @ 987654336@ 来检测 Spyder,在任何一种情况下都提供“更响亮”的警告,并防止代码在后者中中断。

if any('SPYDER' in name for name in os.environ) \
   or 'pythonw.exe' in sys.executable:
    password = raw_input('WARNING: PASSWORD WILL BE SHOWN ON SCREEN\n\n' * 3
                         + 'Please enter your password: ')
else:        
    password = getpass.getpass("Please enter your password: ")

【讨论】:

  • 我可以补充一点,这种方法也适用于 PyCharme IDE,即只需将“SPYDER”替换为“PYCHARM”。
  • 如果用户在他们的环境中有预定义的 SPYDER_something,这将给出一个误报。
  • 如果你想要一个更短的短语(和微小的速度提升)完全指定一个单一的环境变量名称,例如if 'SPYDER_ENCODING' in os.environ.keys():(或者在我的情况下是'PYZO_PREFIX'
  • @mattwilkie 虽然这种方法是有效的,但在这里我主要担心第三方项目会更改它在未来版本中设置的特定环境变量,从而在我的代码中引入错误。就证书而言,采取防御措施是值得的。我认为没有理由期望即使在最坏的情况下,python 也会花费很长时间来搜索 os.environsys.executable 以影响用户的体验。但如果您有理由期待其他情况,我可以看到更积极的优化。
  • @Air 对我来说,我喜欢 if X in Y 的主要原因是更短的短语。我不需要停下来思考附加的Y for Y in Z 做了什么。执行速度的提高只是一个愉快的副产品。但是,我只对与您的场景不同的 1 个特定 var 感兴趣。
【解决方案2】:

默认情况下,Spyder 使用启动脚本,请参阅首选项 -> 控制台 -> 高级设置。该选项通常设置为加载pylab等的scientific_startup.py文件。

最简单的解决方案是在文件中添加一个全局变量,然后在 if 语句中使用它,例如在scientific_startup.py末尾添加这一行:

SPYDER_IDE_ACTIVE = True

在您的脚本中:

if not 'SPYDER_IDE_ACTIVE' in globals():
    use getpass
else:
    use alternative

这将正常工作而不会引发错误。如果您更喜欢,也可以使用异常。

第二种解决方案是(如果您由于某种原因无法修改该文件)检查是否设置了环境变量 PYTHONSTARTUP。在我的机器上(使用 Anaconda Python 堆栈),它没有设置为常规 Python shell。你可以这样做

import os
if not 'PYTHONSTARTUP' in os.environ:
    use getpass
else:
    use alternative

【讨论】:

  • 谢谢,这很有帮助。建议进行编辑以反映 os.environ 不可调用。
  • 另外,globals() 仅提供模块命名空间,因此在导入调用 getpass 的模块时,您的第一个建议将不起作用。
  • 啊,谢谢。拆了牙套。不过,必须考虑导入的问题。
【解决方案3】:

Spyder 提供了在本机系统终端中执行当前编辑器脚本的选项。这将产生与从命令行运行相同的行为。要进行设置,请点击F6 打开“运行设置”对话框。然后选择单选按钮“在外部系统终端中执行”。现在通过点击F5 像往常一样运行脚本。通过这种方法,您应该能够以正常方式使用getpass

【讨论】:

  • 您还可以在同一个“运行设置”对话框中启用“执行后与 Python 解释器交互”,这将使解释器在代码运行后或引发错误后保持打开状态。
【解决方案4】:

您可以在 Spyder 中运行时添加 env 变量并在代码中检查它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多