将 .py 文件编译成 .pyd 文件

一、简介

1.1、Python文件类型:.py + .pyc + .pyd

py是明文且易读,pyc不易读但易被反编译,pyd不易读且不易被反编译(用于代码加密)。

  • 源代码文件 (.py):Python 的源代码文件以 .py 为扩展名,其中包含了 Python 代码的文本内容。这些文件可以直接编辑,并且可以通过 Python 解释器执行。
  • 字节码文件 (.pyc)当 Python 的源代码文件被导入时,Python 解释器会将其编译成字节码,并将字节码保存在以 .pyc 为扩展名的文件中。这些文件是 Python 解释器优化后的版本,用于加快导入模块的速度。如果 Python 源代码文件发生了改变,Python 解释器会自动重新生成对应的 .pyc 文件。
    • 使用 py_compile 将 .py 文件编译成 .pyc 文件python -m py_compile xxx.py
      • 特点:难以阅读,但很容易被反编译工具反编译回可读的源代码(如: uncompyle6)。
  • 动态链接库 (.pyd):在 Windows 平台上,Python 的扩展模块通常以 .pyd 为扩展名,它们是用 C 或 C++ 编写的,并且提供了对其他语言编写的库和系统调用的接口。.pyd 文件通常包含了用 C 或 C++ 编写的扩展模块,它们可以通过 Python 解释器导入,并且提供了对其它语言编写的库和系统调用的接口。
    • 使用 Cython 将 .py 文件编译成 C 扩展模块,从而生成二进制 .pyc 文件python setup.py build_ext
      • 特点:提高了反编译的难度。但反汇编工具仍可以对二进制文件进行逆向工程,尽管难度更大。编译过程复杂,可能需要配置额外的工具链。

1.2、基本原理

  • 使用函数 Extension() + setup() 构建 setup.py 扩展模块
  • 使用命令 python setup.py build_ext --inplace 生成扩展模块文件
    • Windows平台下,生成 .pyd 文件
    • Unix/Linux平台下,生成 .so 文件

1.2.1、函数详解:Extension() —— 用于定义扩展模块(C/C++ 扩展)的类

"""#########################################################################
# 函数功能:Python 中用于定义扩展模块(C/C++ 扩展)的类。
#         ———— 通过 Extension 类,可以指定扩展模块的名称、源文件的路径、编译选项等信息,从而在构建扩展模块时提供必要的配置。
# 函数说明:Extension(name, sources, include_dirs=None, define_macros=None, undef_macros=None,
#                   library_dirs=None, libraries=None, runtime_library_dirs=None,
#                   extra_objects=None, extra_compile_args=None, extra_link_args=None, export_symbols=None,
#                   swig_opts=None, depends=None, language=None)
# 参数说明:
#       - name:           扩展模块的名称,即在 Python 中导入时使用的名称。
#       - sources:        源文件的路径列表,可以是 .c、.cpp、.pyx 等类型的文件。
#         include_dirs:   包含的头文件目录列表。
#         define_macros:  宏定义列表,例如 [(<macro_name>, <macro_value>)]。
#         undef_macros:   要取消定义的宏列表。
#         library_dirs:   库文件目录列表。
#         libraries:      要链接的库文件列表。
#         runtime_library_dirs:运行时库文件目录列表。
#         extra_objects:  额外的目标文件列表。
#         extra_compile_args:额外的编译选项列表。
#         extra_link_args:额外的链接选项列表。
#         export_symbols: 导出的符号列表。
#         swig_opts:      用于 SWIG 扩展的额外选项。
#         depends:        依赖的文件列表。
#         language:       源文件的编程语言,例如 'c' 或 'c++'。
#########################################################################"""

1.2.2、函数详解:setup() —— 用于配置和构建包的函数

"""#########################################################################
# 函数功能:Python 中用于配置和构建包的函数,通常在 setup.py 脚本中使用。
#         ———— 通过 setup 函数,可以指定包的名称、版本、作者信息、依赖关系、入口点等信息,并配置构建和安装过程。
# 函数说明:setup(**attrs)
# 参数说明:
#         attrs:一个字典,包含了配置信息和选项。常用的参数包括:
#           - name:包的名称。
#             version:包的版本号。
#             author:包的作者名称。
#             author_email:作者的电子邮箱地址。
#             description:包的简要描述。
#             long_description:包的详细描述。
#             packages:包含的子包列表。
#             install_requires:依赖的其他包列表。
#             entry_points:包的入口点。
#           - ext_modules:扩展模块列表。
#             package_data:包含的数据文件列表。
#             scripts:可执行脚本文件列表。
#             classifiers:包的分类列表。
#             license:包的许可证。
#########################################################################"""

二、编译

2.1、环境配置

pip install python
pip install cython

2.2、开始构建

在这里插入图片描述

2.2.1、第一步:构建 setup.py 脚本(需手动指定)

  • 报错提示error: unknown file type '.py' (from 'F:\py\sample.py')
  • 原因分析:试图将 Python 源文件直接传递给 Extension 对象,而它期望的是 C/C++ 源文件。
  • 解决方案:使用 Cython 的 cythonize() 函数,将 Python 文件转换为 C/C++ 扩展模块,然后再将其传递给 Extension 对象。
2.2.1.1、构建 setup.py 脚本(方式一):基于 setup() 函数
from setuptools import setup
from Cython.Build import cythonize

setup(name='my_module', ext_modules=cythonize(r'F:\py\temp\my_module.py'))
2.2.1.2、构建 setup.py 脚本(方式二):基于 Extension() + setup() 函数
from setuptools import setup, Extension
from Cython.Build import cythonize

# 定义(单个)扩展模块
ext_modules = Extension(name="my_module", sources=[r"F:\py\temp\my_module.py"])
"""#####################################################################
# 定义(多个)扩展模块
ext_modules = [
    Extension(name="my_module1", sources=[r"F:\py\temp\my_module1.py"]),
    Extension(name="my_module2", sources=[r"F:\py\temp\my_module2.py"]),
    # 添加更多的扩展模块...
]
#####################################################################"""
# 使用 cythonize() 函数将扩展模块编译为 C/C++ 扩展模块,并将其传递给 ext_modules 参数。
setup(ext_modules=cythonize(ext_modules))

2.2.2、第二步:编译命令:python setup.py build_ext --inplace

在命令行中,执行命令:python setup.py build_ext --inplace

  • python: Python 解释器可执行文件的路径(默认使用环境变量的配置路径)。
  • setup.py:Python 脚本文件,用于定义 Python 包的构建和安装方式。通常,这个文件会包含一些元数据和构建指令,以告诉 setuptools(Python 的一个包管理工具)如何构建和安装这个包。
  • python setup.py:使用 python 命令,执行 Python 脚本文件。
  • build_ext: Python 定义的一个命令,用于构建扩展模块。
  • --inplace:可选。表示编译后的 .pyd 文件保存在默认的构建目录中,复制一份到当前目录中。
    • 默认路径:build\lib.win-amd64-cpython-39\my_module.cp39-win_amd64.pyd

编译后,将在当前路径下生成以下文件:

  • (1)build 文件夹:包含编译过程中的所有中间文件和最终的扩展模块库文件。
  • (2)使用 Cython 工具,将 .py 文件编译成 .c 文件:my_module.c
  • (3)编译后生成二进制 .pyc 文件:my_module.pyd

在这里插入图片描述

2.3、调用 .pyd 文件

步骤一:将 module.py 文件编译成 module.pyd 文件

# module.py
def hello():
    return "Hello, World!"

def add(a, b):
    return a + b

def subtract(a, b):
    return a - b

步骤二:调用 module.pyd 文件中的函数。
备注:如果在同一个路径下同时存在同名的 .py 和 .pyd 文件,Python 解释器将首先优先使用 .py 文件,因为它是 Python 源代码文件。

# main.py
import my_module  # 导入.pyd模块

print(my_module.hello())  # 输出: Hello, World!
print(my_module.add(1, 2))  # 输出: 3
print(my_module.subtract(1, 2))  # 输出: -1

2.3.1、(py转pyd)编译命令必须在py文件所需环境下打包

  • 异常提示:ImportError: DLL load failed: 找不到指定的模块。
  • 解决方案:(py转pyd)编译命令必须在py文件所需环境下打包,如此生成的pyd文件才满足环境要求。

2.3.1、(py转pyd)error: Microsoft Visual C++ 14.0 or greater is required.

"""####################################################################################################################
# (py39) PS C:\Users\my\Desktop\Pycharm> python setup.py build_ext --inplace
# Compiling C:\Users\my\Desktop\Pycharm\example.py because it changed.
# [1/1] Cythonizing C:\Users\my\Desktop\Pycharm\example.py
# E:\Anaconda\envs\py39\lib\site-packages\Cython\Compiler\Main.py:381: FutureWarning: Cython directive 'language_level' not set, using '3str' for now (Py3).
# This has changed from earlier releases! File: C:\Users\my\Desktop\Pycharm\example.py
#   tree = Parsing.p_module(s, pxd, full_module_name)
# running build_ext
# building 'example' extension
# error: Microsoft Visual C++ 14.0 or greater is required. Get it with "Microsoft C++ Build Tools": https://visualstudio.microsoft.com/visual-cpp-build-tools/
# (py39) PS C:\Users\my\Desktop\Pycharm>
####################################################################################################################"""
  • 原因分析:根据错误信息,您的环境缺少构建扩展所需的 Microsoft Visual C++ 14.0 或更高版本。
  • 解决方案:安装 Microsoft Visual C++ 构建工具。
    • (1)下载 Visual C++ 构建工具:Microsoft C++ Build Tools
    • (2)安装 Visual C++ 构建工具:
      • 下载完成后,运行安装程序。
      • 在安装选项中,选择“使用 C++ 的桌面开发”工作负载,这将包含必要的编译器和工具。
      • 点击“安装”按钮,等待安装完成。
    • (3)配置环境变量(如果需要):
      • (自动配置)安装程序会自动配置环境变量。
      • (手动配置)在系统属性 -> 高级 -> 环境变量 -> Path 变量 -> 添加 Visual C++ 构建工具的安装路径:C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64
    • 重试构建:
      • 安装并配置完成后,重新打开命令提示符或者 PowerShell,然后在项目目录下再次运行以下命令:python setup.py build_ext --inplace
"""####################################################################################################################
(py39) PS C:\Users\my\Desktop\Pycharm> python setup.py build_ext --inplace
Compiling C:\Users\my\Desktop\Pycharm\test.py because it changed.
[1/1] Cythonizing C:\Users\my\Desktop\Pycharm\test.py
E:\Anaconda\envs\py39\lib\site-packages\Cython\Compiler\Main.py:381: FutureWarning: Cython directive 'language_level' not set, using '3str' for now (Py3).
    This has changed from earlier releases! File: C:\Users\my\Desktop\Pycharm\test.py
  tree = Parsing.p_module(s, pxd, full_module_name)
running build_ext
building 'test' extension
C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.40.33807\bin\HostX86\x64\cl.exe /c /nologo /Ox /W3/GL /DNDEBUG /MD -IE:\Anaconda\envs\deeplearning36\include -IE:\Anaconda\envs\deeplearning36\include "-IC:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.40.33807\include" "-IC:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\VS\include" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.22621.0\ucrt" "-IC:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\um" "-IC:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\shared" "-IC:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\winrt" "-IC:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\cppwinrt" /TcC:\Users\my\Desktop\Pycharm\test.c /Fobuild\temp.win-amd64-3.6\Release\Users\my\Desktop\Pycharm\test.objtest.c
C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.40.33807\bin\HostX86\x64\link.exe /nologo /INCREMENTAL:NO /LTCG /DLL /MANIFEST:EMBED,ID=2 /MANIFESTUAC:NO /LIBPATH:E:\Anaconda\envs\deeplearning36\libs /LIBPATH:E:\Anaconda\envs\deeplearning36\PCbuild\amd64 "/LIBPATH:C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.40.33807\lib\x64" "/LIBPATH:C:\Program Files (x86)\Windows Kits\10\lib\10.0.22621.0\ucrt\x64" "/LIBPATH:C:\Program Files (x86)\Windows Kits\10\\lib\10.0.22621.0\\um\x64" /EXPORT:PyInit_test build\temp.win-amd64-3.6\Release\Users\my\Desktop\Pycharm\test.obj /OUT:build\lib.win-amd64-3.6\test.cp36-win_amd64.pyd /IMPLIB:build\temp.win-amd64-3.6\Release\Users\my\Desktop\Pycharm\test.cp36-win_amd64.lib
  正在创建库 build\temp.win-amd64-3.6\Release\Users\my\Desktop\Pycharm\test.cp36-win_amd64.lib 和对象 build\temp.win-amd64-3.6\Release\Users\my\Desktop\Pycharm\test.cp36-win_amd64.exp
正在生成代码
已完成代码的生成
copying build\lib.win-amd64-3.6\test.cp36-win_amd64.pyd ->
####################################################################################################################"""

三、异常提示

"""####################################################################################################################
# 已知任务:一、在example_pyqt.py中,使用Python解释器执行命令:激活其他虚拟环境 + 执行example.py文件。
#          二、py转pyd:example_pyqt.py与example.py -> example_pyqt.pyd与example.pyd
#
#     Debug1:conda activate命令将在一个新的子进程中执行,该子进程的环境变量变化不会影响到当前Python进程中运行的后续代码。
#             解决方案:(1)在example_pyqt.py中直接执行example.py文件,而不是调用example.py文件中的函数。
#                      (2)构建命令字符串:激活环境 + 执行.py文件,然后同时传递给 subprocess.run,而不是前后运行两次。
#     Debug2:SyntaxError: Non-UTF-8 code starting with '\x90' in file .pyd, but no encoding declared.
              原因分析:Python解释器只支持Python脚本文件(.py文件),不支持编译后的Python扩展模块(.pyd文件:是一个二进制文件)
#             解决方案:(1)使用 Cython 工具,将 main_funcs.py 转为 main_funcs.pyd。
#                      (2)编写一个Python脚本:main_funcs_runner.py,并调用 main_funcs.pyd 文件中的函数。
#                      (3)在 test.py 中,调用 main_funcs_runner.py。 —— 实现间接调用 main_funcs.pyd文件
#     Debug3:TypeError: The decorated object is not a function (got type <class '_cython_3_0_10.cython_function_or_method'>).
#             原因分析::Numba装饰器只支持Python脚本文件(.py文件),不支持编译后的Python扩展模块(.pyd文件)。
#     Debug4:ImportError: DLL load failed: 找不到指定的模块。
#             原因分析:(py转pyd)打包时必须在py文件所在的环境下,如此打包后的pyd才能满足环境要求。
#             解决方案:(1)将 main_funcs.py 文件中的 Numba 加速部分剥离,并另存为 numba_funcs.py 文件。
#                           在 main_funcs.py 文件中,调用 numba_funcs.py 文件中的 Numba 函数。
#                      (2)使用 Cython 工具,将 main_funcs.py 转为 main_funcs.pyd,且保持 numba_funcs.py 文件不变。
#                      (3)在 test.py 文件中,调用 main_funcs.pyd 或 numba_funcs.py 中的函数。
####################################################################################################################"""

3.1、Python解释器:-m 选项不支持指定模块路径[-m ./path/模块名]。

在这里插入图片描述

  • 异常提示:No module named
  • 原因分析:在Python解释器中,-m 选项只支持指定模块名称[-m 模块名],而不支持同时指定模块路径[-m ./path/模块名]。
  • 解决方案:若模块需要同时指定路径,添加文件路径后再指定模块名称。
import sys
import subprocess

sys.path.append(r'F:\py')                                                       # 添加路径到搜索路径
command = "python -m deeplearning_main"                                         # 构建命令
result = subprocess.run(command, shell=True, capture_output=True, text=True)    # 执行命令

print(f"Executing command: {command}")  # 打印命令
print("stdout:", result.stdout)         # 打印输出结果
print("stderr:", result.stderr)         # 打印输出异常
if result.returncode == 0:              # 检查返回码
    print("Script executed successfully")
else:
    print(f"Script failed with return code {result.returncode}")

3.2、Python解释器:conda activate命令将在新的子进程中执行,且不影响后续代码。

  • 异常提示:conda activate命令会在一个新的子进程中执行,该子进程的环境变量变化不会影响到当前Python进程中运行的后续代码。
  • 解决方案:构建命令字符串:激活环境 + 执行.py文件,然后同时传递给 subprocess.run,而不是前后运行两次。
"""########################################################
import subprocess

conda_env = "deeplearning36"
script_path = "exampl_runner.py"
command1 = f"conda activate {conda_env}"
command2 = f"conda activate {script_path}"
subprocess.run(command1)
subprocess.run(command2)

# 备注:exampl_runner.py将在主函数的环境下执行,而不是新激活环境下。
########################################################"""
import subprocess

conda_env = "deeplearning36"
script_path = "exampl_runner.py"
command = f"conda activate {conda_env} && python {script_path}"  # 激活环境的同时执行py文件
print(f"Executing command: {command}")
try:
    subprocess.run(command)
except subprocess.CalledProcessError as e:
    print(f"Error: {e}")
# 备注:exampl_runner.py将在新激活环境下执行。

3.3、Python解释器:只支持Python脚本文件(.py文件),不支持编译后的Python扩展模块(.pyd文件)。

  • 异常提示:SyntaxError: Non-UTF-8 code starting with '\x90' in file .pyd, but no encoding declared.
  • 原因分析:Python解释器只支持Python脚本文件(.py文件),不支持编译后的Python扩展模块(.pyd文件:是一个二进制文件)。
  • 解决方案:
    • (1)使用 Cython 工具,将 main_funcs.py 转为 main_funcs.pyd。
    • (2)编写一个Python脚本:main_funcs_runner.py,并调用 main_funcs.pyd 文件中的函数。
    • (3)在 test.py 中,调用 main_funcs_runner.py。 —— 实现间接调用 main_funcs.pyd文件

步骤一:编写一个Python脚本:main_funcs_runner.py,并调用 main_funcs.pyd 文件中的函数。

# main_funcs_runner.py
import sys
import example

if __name__ == "__main__":
    load_path = sys.argv[1]
    load_downSampleImage = sys.argv[2]
    load_tempImage = sys.argv[3]
    
    main_funcs.main(load_path, load_downSampleImage, load_tempImage)

步骤二:在 test.py 中,调用 main_funcs_runner.py。 —— 实现间接调用 main_funcs.pyd文件

# test.py
import subprocess

conda_env = "deeplearning36"

script_path = "F:/test/code/exampl_runner.py"
load_path = "path_to_load_path"
load_downSampleImage = "path_to_load_downSampleImage"
load_tempImage = "path_to_load_tempImage"
# 激活环境的同时执行py文件
command = f"conda activate {conda_env} && python {script_path} {load_path} {load_downSampleImage} {load_tempImage}"
print(f"Executing command: {command}")
try:
    subprocess.run(command)
except subprocess.CalledProcessError as e:
    print(f"Error: {e}")

3.4、Numba装饰器:只支持Python脚本文件(.py文件),不支持编译后的Python扩展模块(.pyd文件)。

  • 异常提示:TypeError: The decorated object is not a function (got type <class '_cython_3_0_10.cython_function_or_method'>).
  • 中文解释:Numba试图装饰的对象不是函数,而是一个Cython生成的方法或函数。
  • 原因分析:Numba装饰器仅能用于 .py 文件中的函数,而不能用于Cython工具生成的 .pyd 文件中的函数。
  • 解决方案:
    • (1)将 main_funcs.py 文件中的 Numba 加速部分剥离,并另存为 numba_funcs.py 文件。在 main_funcs.py 文件中,调用 numba_funcs.py 文件中的 Numba 函数。
    • (2)使用 Cython 工具,将 main_funcs.py 转为 main_funcs.pyd,且保持 numba_funcs.py 文件不变。
    • (3)在 test.py 文件中,调用 main_funcs.pyd 或 numba_funcs.py 中的函数。

步骤一:(1)将 main_funcs.py 文件中的 Numba 加速部分剥离,并另存为 numba_funcs.py 文件。(2)在 main_funcs.py 文件中,调用 numba_funcs.py 文件中的 Numba 函数

"""########################################################
import numba

@numba.jit(nopython=True)
def numba_add(a, b):
    return a + b

def main():
    print("result = ", numba_add(1, 2))  # result =  3

if __name__ == '__main__':
    main()
########################################################"""
# main_funcs.py
from numba_funcs import numba_add

def main():
    print("result = ", numba_add(1, 2))

if __name__ == '__main__':
    main()
# numba_funcs.py
import numba

@numba.jit(nopython=True)
def numba_add(a, b):
    return a + b

步骤二:使用 Cython 工具,将 main_funcs.py 转为 main_funcs.pyd,且保持 numba_funcs.py 文件不变。

步骤三:在 test.py 文件中,调用 main_funcs.pyd 或 numba_funcs.py 中的函数。

# main_funcs.py
from numba_funcs import numba_add
from main_funcs import main


def cython_function():
    main()

if __name__ == '__main__':
    cython_function()
    print(f"Result = {numba_add(1, 3)}")
	
"""
result =  3
Result = 4
"""    

四、将 .py 文件编译成 .pyd 文件(自动执行 + 批量执行)

将批量 .py 文件编译成 .pyd 文件。

编译成功的打印信息

"""
Compiling deeplearning.py because it changed.
[1/1] Cythonizing deeplearning.py
省略...
running build_ext
building 'deeplearning' extension
creating build
creating build\temp.win-amd64-3.6
creating build\temp.win-amd64-3.6\Release
省略...
省略...
正在生成代码
已完成代码的生成
copying build\lib.win-amd64-3.6\deeplearning.cp36-win_amd64.pyd ->
deeplearning.cp36-win_amd64.pyd has been generated.
"""
"""##############################################################
# 功能:将批量.py文件编译成.pyd文件。
##############################################################"""
import os
import glob
import shutil


def py2pyd(one_all, del_py, paths):
    """##############################################################
    # 参数说明:
    #         all:      (批量)编译指定目录及其子目录下的所有.py文件
    #         one:      (单个)编译.py文件
    #         del:      编译完成后,删除源文件。注意:无法恢复,谨慎使用!
    #         nodel:    编译完成后,保留源文件。
    ##############################################################"""
    def compile_single_py(path):
        folder_path = os.path.dirname(path)  # 获取文件夹路径
        file_path = os.path.split(path)[1]  # 获取文件名(包括后缀)
        os.chdir(folder_path)  # 改变当前工作目录为 folder_path 所指定的目录
        #############################################################################
        # 在在当前路径下,自动生成一个setup.py文件
        with open('setup.py', 'w') as f:
            f.write('from setuptools import setup\n')
            f.write('from Cython.Build import cythonize\n')
            f.write(f"setup(name='test', ext_modules=cythonize('{file_path}'))")

        # 开始编译setup.py(编译结束,将在当前路径下生成:xxx.cp38-win_amd64.pyd + xxx.c + build文件夹)
        os.system('python setup.py build_ext --inplace')
        #############################################################################
        filename = file_path.split('.py')[0]  # 获取文件名(没有后缀)
        pyd_name = f'{folder_path}\\{filename}.pyd'  # 获取.pyd文件路径
        # 若在当前路径下,已存在同名的.pyd文件,则删除。
        if os.path.exists(pyd_name):
            os.remove(pyd_name)

        """修改.pyd文件名"""
        # 获取.pyd文件的文件名 ———— 如: xxx.cp38-win_amd64.pyd
        amd64_pyd = glob.glob(filename + "*.pyd")  # glob.glob: 获取指定模式下的所有文件名列表
        print("*"*100)
        print(f"{amd64_pyd[0]} has been generated.")
        # 修改.pyd文件的文件名 ———— 如: xxx.pyd,即删除冗余的.cp38-win_amd64
        os.rename(amd64_pyd[0], pyd_name)  # os.rename(old_name, new_name): 将old_name重命名为new_name.

        """删除过程文件"""
        os.remove('setup.py')  # 删除自动生成的setup.py文件
        os.remove(f'{filename}.c')  # 删除自动生成的xxx.c文件
        shutil.rmtree(os.path.join(folder_path, 'build'))  # 删除自动生成的build文件夹及其所有内容。

        """删除.py源文件 ———— 无法恢复,慎用!"""
        if del_py == 'del':
            os.remove(file_path)

    def get_all_file(path):
        """遍历给定目录下的所有.py文件,包含子目录里的.py文件"""
        for root, dirs, files in os.walk(path):
            for name in files:
                if name.endswith(".py"):
                    compile_single_py(os.path.join(root, name))

    if one_all == 'one':
        compile_single_py(paths)  # 若为单个.py文件,则直接执行。
    else:
        get_all_file(paths)       # 若为多个.py文件,则遍历所有文件,并单个执行。


"""##############################################################
# 示例1:批量编译指定目录及其子目录下的所有.py文件
#         py2pyd('all', 'nodel', r'D:\\PYTHON\\toPYD\\test')  # 不删除源文件
#         py2pyd('all', 'del', r'D:\\PYTHON\\toPYD\\test')  # 删除源文件
# 
# 示例2:编译单个.py文件
#         py2pyd('one', 'nodel', r'D:\\PYTHON\\toPYD\\test\\mycode.py')  # 不删除源文件
#         py2pyd('one', 'del', r'D:\\PYTHON\\toPYD\\test\\mycode.py')  # 删除源文件
##############################################################"""
if __name__ == '__main__':
    try:
        from setuptools import setup, Extension
        from Cython.Build import cythonize

        py2pyd('one', 'nodel', r'F:\py\pyinstaller\test.py')
    except ImportError:
        print("cython模块未安装,安装命令(翻墙状态,安装失败):pip install cython")

  • 33
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胖墩会武术

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值