好吧,我有一个 Python 包。在以易于导入的方式分发之前,我需要将其编译为 dll。如何?你可能会建议*.pyc
。但我在某处读到任何*.pyc
可以轻松反编译的地方!
更新:
遵循这些:
1)我写了一个python包
2)想要分发它
3)不想分发源代码
4)* .pyc是可反编译的>>源代码可以被提取!
5)dll是标准的
好吧,我有一个 Python 包。在以易于导入的方式分发之前,我需要将其编译为 dll。如何?你可能会建议*.pyc
。但我在某处读到任何*.pyc
可以轻松反编译的地方!
更新:
遵循这些:
1)我写了一个python包
2)想要分发它
3)不想分发源代码
4)* .pyc是可反编译的>>源代码可以被提取!
5)dll是标准的
在 Cython 中编写您想要隐藏的所有内容,并将其编译为pyd
. 这与制作已编译的 python 代码一样接近。
此外,dll 不是标准,在 Python 世界中也不是。它们也不是便携式的。
现在存在一个简单的解决方案:使用 Nuitka 编译器,如 Nuitka 用户手册中所述
用例 2 - 扩展模块编译如果你想编译单个扩展模块,你所要做的就是:
python -m nuitka --module some_module.py然后可以使用生成的文件 some_module.so 代替 some_module.py。
你需要为你想要支持的每个平台编译并编写一些初始化代码来导入so/pyd文件~~适合给定的平台/python版本等~~
[编辑 2021-12]:实际上在 python 3 中,正确的 so/dll 是根据文件名自动确定的(如果它包括 python 版本和平台 - 目前找不到此功能的 PEP,但 Nuitka 为编译模块)。因此,对于 python 2.7,库名称将是 something.pyd 或 something.so,而对于 python 3,这将更改为 something.cp36-win32.pyd 或 something.cpython-36m-x86_64-linux-gnu.so(对于 32 位 python 3.6在 x86 上)。
结果不是所请求的 DLL,而是 Python 原生编译的二进制格式(它不是 pyc 文件中的字节码;so/pyd 格式不容易反编译 - Nuitka 通过 C++ 翻译编译为机器代码)
编辑 [2020-01]:编译后的模块易于使用 python 标准机制的评估方法 - 例如,它可以作为任何其他模块导入并列出其方法等。为了确保实现不被暴露,还有更多工作要做完成的不仅仅是编译成二进制模块。
您可以将 python 嵌入到 C中。真正的技巧是在 C 值和 Python 值之间进行转换。但是,一旦你完成了这些,制作一个 DLL 就非常简单了。
但是,为什么需要制作一个dll?你需要从非python程序中使用它吗?
您可以使用py2exe.org将 python 脚本转换为 windows 可执行文件。当然,这仅适用于 Windows,但总比没有好。
CFFI 1.5 版支持 Python 嵌入,您可以创建一个.dll
可供 Windows C 应用程序使用的文件。
我也会使用Cython来生成pyd
文件,就像 Dikei 写的那样。但是如果你真的想保护你的代码,你最好用 C++ 编写重要的东西。最好的办法是结合C++和Python。这个想法:你可以让 python 代码打开以进行调整,这样你就不必一遍又一遍地编译所有东西。dll
这意味着,您将用 C++ 编写“核心”(这是当今最安全的解决方案)并在您的 python 代码中使用这些文件。这实际上取决于您正在构建什么样的工具或程序以及您希望如何执行它。完成工具或程序后,我主要创建一个执行文件 ( exe
, app
),但这更多是针对最终用户的。这可以通过py2exe
和py2app
(均兼容 64 位)。如果您实现解释器,则最终用户的机器不必在系统上安装 python。
pyd
文件与 a 相同,并且dll
在 python 中完全受支持。所以你可以正常导入你的模块。您可以在此处找到有关它的更多信息。
使用和生成pyd
文件是创建安全且可移植的 python 代码的最快和最简单的方法。
您还可以在C++中编写真实dll
文件并导入它们以使用它们(这里是一篇好文章,这里是Python对其工作原理的描述)ctypes
扩大尼克奥德尔的答案
您必须在 Windows 上才能使 DLL 工作,它们不可移植。
然而,下面的代码是跨平台的,所有平台都支持运行时,因此可以为您需要它工作的每个平台重新编译。
Python(尚未)提供创建 dll 的简单工具,但是您可以在 C/C++ 中完成
首先,您需要一个编译器(Windows 默认没有),特别是 Cygwin、MinGW 或 Visual Studio。
C 的基本知识也是必要的(因为我们将主要使用 C 进行编码)。
您还需要包含必要的标题,我会跳过它,这样它就不会变得太长,并且会假设一切都设置正确。
对于这个演示,我将打印一个传统的 hello world:
我们将转换为 DLL 的 Python 代码:
def foo(): print("hello world")
C代码:
#include "Python.h" // Includes everything to use the Python-C API
int foo(void); // Declare foo
int foo(void) { // Name of our function in our DLL
Py_Initialize(); // Initialise Python
PyRun_SimpleString("print('hello world')"); // Run the Python commands
return 0; // Finish execution
}
这是嵌入 Python 的教程。这里应该添加一些额外的东西,但为了简洁起见,我把它们省略了。
编译它,你应该有一个 DLL。:)
这还不是全部。您将需要分发所需的任何依赖python36.dll
项,这意味着运行时和其他一些组件来运行 Python 脚本。
我的 C 编码并不完美,所以如果有人能发现任何改进,请发表评论,我会尽力修复它。
从这个答案中,C# 中也有可能How do I call a specific Method from a Python Script in C#? ,因为 C# 可以创建 DLL,并且您可以从 C# 调用 Python 函数。
您可以使用pyinstaller将 .py 文件转换为可执行文件,并将所有必需的包转换为 .dll 格式。
步骤 1. pip install pyinstaller,
步骤 2. 新的 python 文件让我们将其命名为 code.py 。
步骤 3. 编写一些代码行,即 print("Hello World")
步骤 4. 在同一位置打开命令提示符并编写 pyinstaller code.py 回车。最后一步在同一位置看到两个文件夹名称 build,dist 将被创建。在 dist 文件夹内有文件夹代码,在该文件夹内有一个 exe 文件 code.exe 以及所需的 .dll 文件。
如果您的唯一目标是隐藏源代码,那么只需将代码编译为可执行文件(例如,使用 PyInstaller),并使用具有可读源代码的模块进行通信,就会简单得多。注意:您可能需要更多转换器功能,如本示例所示。示例:模块:
import subprocess
import codecs
def _encode_str(str):
encoded=str.encode("utf-32","surrogatepass")
return codecs.encode(encoded,"base64").replace(b"\n",b"")
def _decode_str(b64):
return codecs.decode(b64,"base64").decode("utf-32","surrogatepass")
def strlen(s:str):#return length of str;int
proc=subprocess.Popen(["path_to_your_exe.exe","strlen",_encode_str(str).decode("ascii")],stdout=subprocess.PIPE)
return int(proc.stdout.read())
def random_char_from_string(str):
proc=subprocess.Popen(["path_to_your_exe.exe","randchr",_encode_str(str).decode("ascii")],stdout=subprocess.PIPE)
return _decode_str(proc.stdout.read())
可执行文件:
import sys
import codecs
import random
def _encode_str(str):
encoded=str.encode("utf-32","surrogatepass")
return codecs.encode(encoded,"base64").replace(b"\n",b"")
def _decode_str(b64):
return codecs.decode(b64,"base64").decode("utf-32","surrogatepass")
command=sys.argv[1]
if command=="strlen":
s=_decode_str(sys.argv[2].encode("ascii"))
print(len(str))
if command=="randchr":
s_decode_str(sys.argv[2].encode("ascii"))
print(_encode_str(random.choice(s)).decode("ascii"))
如果您的包不是仅适用于 Windows 的包,您可能还想考虑为不同的平台编译不同的可执行文件。
这是我的想法,它可能会奏效。我不知道,这是否有效。
1.创建您的*.py
文件。
2.将它们重命名为 3.使用 Cython 将它们转换为文件 4.
编译*.pyx
成文件。 *.c
*.c
*.dll
但我不推荐你,因为它不能在任何其他平台上运行,除了 Windows。
抓住 Visual Studio Express 和 IronPython 并这样做?不过,您将进入 Python 2.7.6 世界。