为什么python不需要编译_为什么Python编译模块而不是正在运行的脚本?

指向实现关注项的源代码。这解释了"为什么"从技术意义上讲:唤起这种行为需要哪些先决条件?

指向参与制定决策的开发人员编写的人类可读工件(评论,提交消息,电子邮件列表等)。这才是真正意义上的"为什么"我认为OP感兴趣的是:为什么Python的开发人员做出这个看似随意的决定?

醇>

第二种类型的答案更难以证实,因为它需要了解编写代码的开发人员的想法,特别是如果没有易于查找的公共文档解释特定决策。

到目前为止,这个主题有7个答案,专注于阅读Python开发人员的意图,但整批中只有一个引用。 (它引用了Python手册的一部分,不回答O​​P的问题。)

这是我尝试回答""为什么"问题以及引用。

源代码

触发编译.pyc的前提条件是什么?我们来看the source code。 (令人恼火的是,GitHub上的Python没有任何发布标签,所以我只是告诉你我正在看715a6e。)

import.c:989函数中的load_source_module()代码很有用。为简洁起见,我在这里删掉了一些内容。

static PyObject *

load_source_module(char *name, char *pathname, FILE *fp)

{

// snip...

if (/* Can we read a .pyc file? */) {

/* Then use the .pyc file. */

}

else {

co = parse_source_module(pathname, fp);

if (co == NULL)

return NULL;

if (Py_VerboseFlag)

PySys_WriteStderr("import %s # from %s\n",

name, pathname);

if (cpathname) {

PyObject *ro = PySys_GetObject("dont_write_bytecode");

if (ro == NULL || !PyObject_IsTrue(ro))

write_compiled_module(co, cpathname, &st);

}

}

m = PyImport_ExecCodeModuleEx(name, (PyObject *)co, pathname);

Py_DECREF(co);

return m;

}

pathname是模块的路径,cpathname是相同的路径,但扩展名为.pyc。唯一的直接逻辑是布尔值sys.dont_write_bytecode。其余的逻辑只是错误处理。所以我们寻求的答案不在这里,但我们至少可以看到,调用此代码的任何代码都会在大多数默认配置下生成.pyc文件。 parse_source_module()函数与执行流程没有实际关联,但我会在此处显示它,因为我稍后会再回过头来看。

static PyCodeObject *

parse_source_module(const char *pathname, FILE *fp)

{

PyCodeObject *co = NULL;

mod_ty mod;

PyCompilerFlags flags;

PyArena *arena = PyArena_New();

if (arena == NULL)

return NULL;

flags.cf_flags = 0;

mod = PyParser_ASTFromFile(fp, pathname, Py_file_input, 0, 0, &flags,

NULL, arena);

if (mod) {

co = PyAST_Compile(mod, pathname, NULL, arena);

}

PyArena_Free(arena);

return co;

}

这里的显着方面是函数解析并编译文件并返回指向字节代码的指针(如果成功)。

现在我们仍处于死胡同,所以让我们从一个新的角度来看待这个问题。 Python如何加载它的参数并执行它?在pythonrun.c中,有一些函数可以从文件加载代码并执行它。 PyRun_AnyFileExFlags()可以处理交互式和非交互式文件描述符。对于交互式文件描述符,它委托给PyRun_InteractiveLoopFlags()(这是REPL),对于非交互式文件描述符,它委托给PyRun_SimpleFileExFlags()。 PyRun_SimpleFileExFlags()检查文件名是否以.pyc结尾。如果是,则调用run_pyc_file()直接加载文件描述符中的编译字节代码,然后运行它。

在更常见的情况下(即.py文件作为参数),PyRun_SimpleFileExFlags()调用PyRun_FileExFlags()。这是我们开始找到答案的地方。

PyObject *

PyRun_FileExFlags(FILE *fp, const char *filename, int start, PyObject *globals,

PyObject *locals, int closeit, PyCompilerFlags *flags)

{

PyObject *ret;

mod_ty mod;

PyArena *arena = PyArena_New();

if (arena == NULL)

return NULL;

mod = PyParser_ASTFromFile(fp, filename, start, 0, 0,

flags, NULL, arena);

if (closeit)

fclose(fp);

if (mod == NULL) {

PyArena_Free(arena);

return NULL;

}

ret = run_mod(mod, filename, globals, locals, flags, arena);

PyArena_Free(arena);

return ret;

}

static PyObject *

run_mod(mod_ty mod, const char *filename, PyObject *globals, PyObject *locals,

PyCompilerFlags *flags, PyArena *arena)

{

PyCodeObject *co;

PyObject *v;

co = PyAST_Compile(mod, filename, flags, arena);

if (co == NULL)

return NULL;

v = PyEval_EvalCode(co, globals, locals);

Py_DECREF(co);

return v;

}

这里的重点是这两个功能基本上与导入器load_source_module()和parse_source_module()的功能相同。它调用解析器从Python源代码创建AST,然后调用编译器创建字节码。

这些代码块是多余的还是它们用于不同的目的?区别在于一个块从文件加载模块,而另一个块将模块作为参数。该模块参数是 - 在这种情况下 - __main__模块,它是在初始化过程中使用低级C函数创建的。 __main__模块没有经过大多数普通模块导入代码路径,因为它是如此独特,而且作为副作用,它不会通过生成{{1}的代码。文件。

总结一下:.pyc模块未编译为.pyc的原因是它没有"#34;导入"。是它出现在sys.modules中,但它通过一个与实际模块导入完全不同的代码路径到达那里。

开发者意图

好的,我们现在可以看到这种行为更多地与Python的设计有关,而不是源代码中任何明确表达的理由,但这并不能回答这是否是故意决定的问题或者只是一个副作用,不会打扰任何人值得改变。开源的一个好处是,一旦我们找到了我们感兴趣的源代码,我们就可以使用VCS来帮助追溯导致当前实现的决策。

这里关键的代码行之一(__main__)可以追溯到1990年,由BDFL自己编写,Guido。它在中间进行了修改,但修改是肤浅的。首次编写时,脚本参数的主模块初始化如下:

m = PyImport_AddModule("__main__");

在将int

run_script(fp, filename)

FILE *fp;

char *filename;

{

object *m, *d, *v;

m = add_module("`__main__`");

if (m == NULL)

return -1;

d = getmoduledict(m);

v = run_file(fp, filename, file_input, d, d);

flushline();

if (v == NULL) {

print_error();

return -1;

}

DECREF(v);

return 0;

}文件引入Python之前就已经存在了!难怪当时的设计没有考虑脚本参数的编译。 commit message神秘地说:

"编译"版本

这是3天内几十次提交之一...... Guido似乎深陷一些黑客攻击/重构,这是第一个恢复稳定的版本。这个提交甚至早于the Python-Dev mailing list创建大约五年!

这仍然在列表服务之前,所以我们并不知道Guido在想什么。看起来他只是认为导入器是为了缓存字节码而挂钩的最佳位置。他是否认为为.pyc做同样的事情的想法尚不清楚:要么他没有发生,要么他认为这比它的价值更麻烦。

我无法在bugs.python.org上找到与缓存主模块字节码相关的any bugs,也无法在邮件列表中找到有关它的任何消息,所以显然没有其他人认为尝试添加它是值得的。

总结一下:将所有模块编译到__main__除.pyc以外的原因是它是历史的一个小问题。如何设计和实现{在__main__文件存在之前,{1}}工作已经被编入代码中。如果你想了解更多,你需要通过电子邮件发送Guido并询问。

格伦梅纳德的回答说:

似乎没有人想这样说,但我很确定答案很简单:这种行为没有充分理由。

我同意100%。有支持这一理论的间接证据,这个主题中没有其他人提供过一丝证据来支持任何其他理论。我赞成格伦的答案。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【优质项目推荐】 1、项目代码均经过严格本地测试,运行OK,确保功能稳定后才上传平台。可放心下载并立即投入使用,若遇到任何使用问题,随时欢迎私信反馈与沟通,博主会第一时间回复。 2、项目适用于计算机相关专业(如计科、信息安全、数据科学、人工智能、通信、物联网、自动化、电子信息等)的在校学生、专业教师,或企业员工,小白入门等都适用。 3、该项目不仅具有很高的学习借鉴价值,对于初学者来说,也是入门进阶的绝佳选择;当然也可以直接用于 毕设、课设、期末大作业或项目初期立项演示等。 3、开放创新:如果您有一定基础,且热爱探索钻研,可以在此代码基础上二次开发,进行修改、扩展,创造出属于自己的独特应用。 欢迎下载使用优质资源!欢迎借鉴使用,并欢迎学习交流,共同探索编程的无穷魅力! 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。
Python中,可以使用unluac模块来反编译luac_Lua程序。具体步骤如下: 1. 安装unluac模块。可以使用pip命令进行安装,命令如下: ``` pip install unluac ``` 2. 编写Python脚本来调用unluac模块进行反编译。以下是一个简单的示例脚本: ``` import unluac with open('test.luac', 'rb') as f: data = f.read() decompiled = unluac.decompile(data) with open('test.lua', 'w') as f: f.write(decompiled) ``` 该脚本将test.luac文件反编译为test.lua文件。 3. 将反编译后的Lua代码导入到IDA Pro中。可以使用IDA Pro的Lua插件进行处理。 1. 在IDA Pro中,选择File -> Script file,打开Lua脚本窗口。 2. 在窗口中输入以下代码: ``` local f = io.open("test.lua", "r") local content = f:read("*all") f:close() LoadSource(content, "test.lua") ``` 3. 点击Run按钮,将Lua代码加载到IDA Pro中。 4. 编写IDA Pro处理器模块。可以使用IDA Pro的Python API编写处理器模块,对Lua代码进行分析和处理。以下是一个示例模块: ``` import idaapi class LuaProcessor(idaapi.processor_t): id = 0x8000 + 1 flag = idaapi.PR_USE32 | idaapi.PR_DEFSEG32 cnbits = 8 dnbits = 8 psnames = ["luac"] plnames = ["Luac bytecode"] segreg_size = 0 instruc_start = 0 assembler = { "flag" : flag, "uflag" : 0, "name" : "Luac assembler", "origin" : "luac", "notify" : None, "header" : None, "footer" : None, "segstart" : None, "segend" : None, "assume" : None, "flag2" : 0, "cmnt" : ";", "ascsep" : '"', "accsep" : "'", "esccodes" : "\"'", "a_ascii" : "db", "a_byte" : "db", "a_word" : "dw", "a_dword" : "dd", "a_qword" : "dq", "a_oword" : "xmmword", "a_float" : "dd", "a_double" : "dq", "a_tbyte" : "dt", "a_packreal" : "dq", "a_dups" : "#dups", "a_bss" : "res", "a_seg" : "seg", "a_curip" : "$", "a_public" : "public", "a_weak" : "weak", "a_extrn" : "extrn", "a_comdef" : "comm", "a_align" : "align", "lbrace" : "(", "rbrace" : ")", "a_mod" : "%", "a_band" : "&", "a_bor" : "|", "a_xor" : "^", "a_bnot" : "~", "a_shl" : "<<", "a_shr" : ">>", "a_sizeof_fmt" : "size %s", } def PROCESSOR_ENTRY(): return LuaProcessor() ``` 该模块将Lua代码识别为Luac bytecode,并使用Luac assembler进行处理。 以上就是使用Python编译luac_Lua程序并为其编写IDA Pro处理器模块的一般步骤。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值