Windows 上的 Python 常见问题¶
如何在 Windows 下运行 Python 程序?¶
这不一定是一个简单的问题。如果您已经熟悉从 Windows 命令行运行程序,那么一切都会显得很明显;否则,您可能需要一些额外的指导。
除非您使用某种集成开发环境,否则您最终会在被称为“命令提示符窗口”中键入 Windows 命令。通常,您可以通过在搜索栏中搜索 cmd
来创建一个这样的窗口。您应该能够识别何时启动了这样一个窗口,因为您会看到一个 Windows “命令提示符”,它通常看起来像这样
C:\>
字母可能不同,后面可能还有其他内容,因此您也可能很容易看到类似这样的内容
D:\YourName\Projects\Python>
这取决于您的计算机是如何设置的以及您最近还用它做了什么。一旦您启动了这样一个窗口,您就离运行 Python 程序不远了。
您需要意识到您的 Python 脚本必须由另一个名为 Python 解释器的程序处理。解释器读取您的脚本,将其编译成字节码,然后执行字节码来运行您的程序。那么,您如何安排解释器处理您的 Python 呢?
首先,您需要确保您的命令窗口将“py”这个词识别为启动解释器的指令。如果您已经打开了一个命令窗口,您应该尝试输入命令 py
并按回车键
C:\Users\YourName> py
然后您应该会看到类似这样的内容
Python 3.6.4 (v3.6.4:d48eceb, Dec 19 2017, 06:04:45) [MSC v.1900 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
您已经在“交互模式”下启动了解释器。这意味着您可以交互式地输入 Python 语句或表达式,并在您等待时执行或求值它们。这是 Python 最强大的功能之一。通过输入一些您选择的表达式并查看结果来检查它
>>> print("Hello")
Hello
>>> "Hello" * 3
'HelloHelloHello'
许多人将交互模式用作方便但高度可编程的计算器。当您想要结束交互式 Python 会话时,调用 exit()
函数或在输入 Z 时按住 Ctrl 键,然后按 “Enter” 键以返回到您的 Windows 命令提示符。
您可能还会发现您有一个“开始”菜单项,例如 >>>
提示符。如果是这样,在您调用 exit()
函数或输入 Ctrl-Z 字符后,该窗口将消失;Windows 在窗口中运行单个 “python” 命令,并在您终止解释器时关闭它。
现在我们知道 py
命令已被识别,您可以将您的 Python 脚本交给它。您必须提供 Python 脚本的绝对路径或相对路径。假设您的 Python 脚本位于您的桌面,名为 hello.py
,并且您的命令提示符已在您的主目录中很好地打开,因此您会看到类似于这样的内容
C:\Users\YourName>
现在您将通过输入 py
后跟您的脚本路径来要求 py
命令将您的脚本交给 Python
C:\Users\YourName> py Desktop\hello.py
hello
如何使 Python 脚本可执行?¶
在 Windows 上,标准的 Python 安装程序已经将 .py 扩展名与文件类型 (Python.File) 相关联,并为该文件类型提供了一个运行解释器的打开命令 (D:\Program Files\Python\python.exe "%1" %*
)。这足以使脚本可以从命令提示符中作为 ‘foo.py’ 执行。如果您希望能够通过简单地键入 ‘foo’ 而不带扩展名来执行脚本,则需要将 .py 添加到 PATHEXT 环境变量中。
为什么 Python 有时启动需要很长时间?¶
通常,Python 在 Windows 上启动非常快,但偶尔会出现 Python 突然开始需要很长时间才能启动的错误报告。更令人困惑的是,Python 在其他配置相同的 Windows 系统上可以正常工作。
问题可能是由问题机器上的病毒检查软件配置错误引起的。已知某些病毒扫描程序在配置为监视来自文件系统的所有读取时,会引入两个数量级的启动开销。尝试检查系统上的病毒扫描软件的配置,以确保它们的配置确实相同。McAfee 在配置为扫描所有文件系统读取活动时尤其如此。
如何从 Python 脚本创建一个可执行文件?¶
有关可用于制作可执行文件的工具列表,请参阅 如何从 Python 脚本创建独立的二进制文件?。
*.pyd
文件与 DLL 相同吗?¶
是的,.pyd 文件是 dll,但有一些区别。如果您有一个名为 foo.pyd
的 DLL,那么它必须有一个函数 PyInit_foo()
。然后您可以编写 Python “import foo”,Python 将搜索 foo.pyd(以及 foo.py,foo.pyc),如果找到它,将尝试调用 PyInit_foo()
来初始化它。您不会将您的 .exe 与 foo.lib 链接,因为这会导致 Windows 要求 DLL 存在。
请注意,foo.pyd 的搜索路径是 PYTHONPATH,而不是 Windows 用于搜索 foo.dll 的路径。此外,foo.pyd 不需要存在即可运行您的程序,而如果您将程序与 dll 链接,则需要 dll。当然,如果您想说 import foo
,则需要 foo.pyd。在 DLL 中,链接在源代码中使用 __declspec(dllexport)
声明。在 .pyd 中,链接是在可用函数列表中定义的。
如何将 Python 嵌入到 Windows 应用程序中?¶
将 Python 解释器嵌入到 Windows 应用程序中可以概括如下
不要直接将 Python 构建到您的 .exe 文件中。在 Windows 上,Python 必须是一个 DLL,才能处理导入本身就是 DLL 的模块。(这是第一个未记录的关键事实。)相反,链接到
pythonNN.dll
;它通常安装在C:\Windows\System
中。NN 是 Python 版本,一个数字,例如 Python 3.3 的 “33”。您可以通过两种不同的方式链接到 Python。加载时链接意味着链接到
pythonNN.lib
,而运行时链接意味着链接到pythonNN.dll
。(一般说明:pythonNN.lib
是与pythonNN.dll
相对应的所谓“导入 lib”。它仅为链接器定义符号。)运行时链接极大地简化了链接选项;一切都在运行时发生。您的代码必须使用 Windows 的
LoadLibraryEx()
例程加载pythonNN.dll
。代码还必须使用 Windows 的GetProcAddress()
例程获取的指针来访问pythonNN.dll
中的例程和数据(即 Python 的 C API)。宏可以使使用这些指针对调用 Python C API 中例程的任何 C 代码都是透明的。如果您使用 SWIG,则可以轻松创建一个 Python“扩展模块”,使应用程序的数据和方法可供 Python 使用。SWIG 将为您处理几乎所有繁琐的细节。结果是您链接到 .exe 文件中的 C 代码!您不必创建 DLL 文件,这也简化了链接。
SWIG 将创建一个 init 函数(一个 C 函数),其名称取决于扩展模块的名称。例如,如果模块的名称为 leo,则 init 函数将被调用为 initleo()。如果您使用 SWIG 影子类,正如您应该的那样,则 init 函数将被调用为 initleoc()。这将初始化一个主要由影子类使用的隐藏辅助类。
您可以在步骤 2 中将 C 代码链接到 .exe 文件中的原因是,调用初始化函数等效于将模块导入 Python! (这是第二个关键的未公开的事实。)
简而言之,您可以使用以下代码来初始化带有扩展模块的 Python 解释器。
#include <Python.h> ... Py_Initialize(); // Initialize Python. initmyAppc(); // Initialize (import) the helper class. PyRun_SimpleString("import myApp"); // Import the shadow class.
如果使用 MSVC 以外的编译器(用于构建 pythonNN.dll 的编译器),Python 的 C API 会出现两个问题,这将变得很明显。
问题 1:所谓的“非常高级”函数接受
FILE *
参数,它们在多编译器环境中不起作用,因为每个编译器对struct FILE
的概念是不同的。从实现的角度来看,这些是非常底层的函数。问题 2:SWIG 在生成 void 函数的包装器时会生成以下代码
Py_INCREF(Py_None); _resultobj = Py_None; return _resultobj;
唉,Py_None 是一个宏,它扩展为对 pythonNN.dll 内部名为 _Py_NoneStruct 的复杂数据结构的引用。同样,此代码在多编译器环境中将失败。请将此类代码替换为
return Py_BuildValue("");
可以使用 SWIG 的
%typemap
命令自动进行更改,尽管我还没有成功(我是一个完全的 SWIG 新手)。使用 Python shell 脚本从您的 Windows 应用程序内部弹出 Python 解释器窗口不是一个好主意;结果窗口将独立于您的应用程序的窗口系统。相反,您(或 wxPythonWindow 类)应该创建一个“本机”解释器窗口。将该窗口连接到 Python 解释器很容易。您可以将 Python 的 i/o 重定向到支持读取和写入的任何对象,因此您只需要一个包含 read() 和 write() 方法的 Python 对象(在您的扩展模块中定义)。
如何防止编辑器在我的 Python 源代码中插入制表符?¶
FAQ 不建议使用制表符,而 Python 样式指南 PEP 8 建议将 4 个空格用于分布式 Python 代码;这也是 Emacs python-mode 的默认设置。
在任何编辑器下,混合使用制表符和空格都不是一个好主意。MSVC 在这方面也不例外,并且可以轻松配置为使用空格:选择
,对于文件类型“默认”,将“制表符大小”和“缩进大小”设置为 4,然后选择“插入空格”单选按钮。如果混合的制表符和空格导致前导空格出现问题,Python 将引发 IndentationError
或 TabError
。您也可以运行 tabnanny
模块以在批处理模式下检查目录树。
如何在不阻塞的情况下检查按键?¶
使用 msvcrt
模块。这是一个标准的 Windows 特定扩展模块。它定义了一个函数 kbhit()
,该函数检查是否存在键盘按键,以及 getch()
,该函数获取一个字符而不回显它。
如何解决缺少 api-ms-win-crt-runtime-l1-1-0.dll 错误?¶
当在没有安装所有更新的 Windows 8.1 或更早版本上使用 Python 3.5 及更高版本时,可能会发生这种情况。首先确保您的操作系统受支持并且是最新的,如果这不能解决问题,请访问 Microsoft 支持页面,以获取有关手动安装 C 运行时更新的指导。