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()
函数,或按住Ctrl键,同时输入Z,然后按“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
。它仅仅为链接器定义符号。)运行时链接极大地简化了链接选项;所有操作都在运行时发生。您的代码必须使用 Windows
LoadLibraryEx()
例程加载pythonNN.dll
。代码还必须使用pythonNN.dll
中的访问例程和数据(即 Python 的 C API),使用通过 WindowsGetProcAddress()
例程获得的指针。宏可以使使用这些指针对调用 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.
Python 的 C API 有两个问题,如果您使用除 MSVC 之外的编译器(用于构建 pythonNN.dll 的编译器),这些问题将变得明显。
问题 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 新手)。在 Windows 应用程序中使用 Python shell 脚本启动 Python 解释器窗口不是一个好主意;生成的窗口将独立于应用程序的窗口系统。相反,您(或 wxPythonWindow 类)应该创建一个“原生”解释器窗口。将该窗口连接到 Python 解释器很容易。您可以将 Python 的 I/O 重定向到任何支持读写操作的对象,因此您只需要一个包含 read() 和 write() 方法的 Python 对象(在您的扩展模块中定义)。
如何阻止编辑器在我的 Python 源代码中插入制表符?¶
FAQ 不建议使用制表符,Python 风格指南,PEP 8,建议在分发的 Python 代码中使用 4 个空格;这也是 Emacs python-mode 的默认设置。
在任何编辑器中,混合使用制表符和空格都是一个坏主意。MSVC 在这方面没有区别,并且可以轻松配置为使用空格:选择
,对于文件类型“默认”,将“制表符大小”和“缩进大小”设置为 4,并选择“插入空格”单选按钮。如果混合使用制表符和空格导致前导空格出现问题,Python 会引发 IndentationError
或 TabError
。您也可以运行 tabnanny
模块以批处理模式检查目录树。
如何检查按键而不阻塞?¶
使用 msvcrt
模块。这是一个标准的 Windows 特定扩展模块。它定义了一个函数 kbhit()
,用于检查是否存在键盘按键,以及 getch()
,用于获取一个字符而不回显它。
如何解决缺少 api-ms-win-crt-runtime-l1-1-0.dll 错误?¶
这可能发生在 Python 3.5 及更高版本中,当使用 Windows 8.1 或更早版本且未安装所有更新时。首先确保您的操作系统受支持并已更新,如果这不能解决问题,请访问 Microsoft 支持页面 获取有关手动安装 C 运行时更新的指南。