Python PEP 302 是什么?

hooopo · 2012年08月13日 · 最后由 bhuztez 回复于 2012年08月13日 · 4469 次阅读
共收到 15 条回复

这东西的上下文是什么? 是因为什么东西翻到这个上面的.

我粗看感觉是: 2.3 以前的 python import 机制太挫了, 就实现了一个新的 import 机制.

这个问我就可以了。我都被Django整得快成PEP 302砖家了...

#3楼 @bhuztez 就是来问你的呀.............

#4楼 @hooopo 问题是你现在问得也太宽了吧,我从哪里说起都不知道

#5楼 @bhuztez 我貌似看明白一点儿 说是可以从zip文件里import

#6楼 @hooopo 这坑太大,从zip文件里import只是其中一个很小的应用而已...

#7楼 @bhuztez 讲讲其他的应用哇

#8楼 @hooopo 这个问题比较乱,我思路也没理清楚。我就尽量讲一下我现在对这个问题的认识好了。

这个问题和操作系统有关系,和语言也有关系。或者你可以把一个语言的运行期看成一个操作系统。

首先来看UNIX: Everything is a file。假如Everything is a file只是字面意思,那等于啥都没说。其实这里有两个问题,到哪里去找文件,怎么操作文件。

对于第一个问题,UNIX的答案是一个树形的File System/Namespace。在这里不对这两个概念进行区分。

对于第二个问题,UNIX的答案是统一的API/Interface/Protocol/Message。在这里不对这三个概念进行区分。

接着来看Smalltalk: Everything is an object。类似的。同样有这两个问题。而对于第一个问题的答案,经典的Smalltalk 80并不比UNIX更好,Smalltalk 80就直接让你在名字前面加前缀来区分,就相当于你需要把它脑补成树形的。

对于第一个问题同时也隐含着,一切都可以以文件的形式暴露在文件系统上。这也就是你可以看见/proc/sys这类的目录的原因。

这就是为什么Plan 9有file server,Hurd有Translator。Linux后来也引入了Fuse。也就是说,有了这个机制和对应的file server,你可以把一个zip文件,mount成一个目录,可以直接把可以通过HTTP/FTP访问到的远端文件mount成一个本地文件。

假如所有操作系统都原生有这样的机制的话,Python就没有必要引入PEP 302的概念。PEP 302就是定义了一组API,让你可以把任何东西,无论它以什么形式存在或者不存在,以Python object的形式import到Python命名空间里,只要你实现了这组API。

前几天在Hacker News上提到的Bitey ,无非就是为LLVM bitcode实现了这组API罢了。

但是,PEP-302只是一个work-around,只能为Python解决一小部分的问题。Python进程运行的时候,事实上有两个独立的namespace,一个是操作系统的,一个是Python的。这也导致了很多麻烦。按照Python惯例,并不会把操作系统的namespace映射到Python的namespace里,也不会把Python的namespace映射到操作系统的namespace。很多程序,同时会需要一些静态文件,比如图片啥的。而PEP-302只定义了get_data,这其实是远远不够的。而且,即便所有API都定义好了,这仍然不够好,尽管这对目前的Python来说很可能是唯一的办法。这将导致你为同一件事写了两份代码。

我觉得要真正解决这个问题,得使用Plan 9那样的操作系统,把Python的namespace暴露成/python,能用Python实现file server,另外,Python得实现像Erlang那样的抢占式调度,那还是Python么?我觉得可能还是直接在Erlang的基础上改比较靠谱,至少,Erlang是抢占式调度的,并且也有真正的namespace实现(尽管几乎所有人都用前缀)。

#9楼 @hooopo 相关的一个问题。Ruby里面require到底会干哪些事?Ruby里require的语义和Python的import不太一样吧。

Python里面一个模块就对应一个文件,import之后,就相当于是一个寄生在sys.modules下的dict,所以importer的实现可以很简单。

#11楼 @bhuztez Ruby里的require/load很简单,就是把文件加载到环境里。

require "file_path" 相当于下面的伪代码:

file_content = File.read("file_path")
eval(file_content)

#12楼 @hooopo 这个还真和Python的import有点不一样啊。

__import__(xxx)

相当于

content = read("xxx.py")
module = new_module()
eval content at module
sys.modules['xxx'] = module

import xxx的时候,就是引用sys.modules['xxx']没有就__import__

而在Ruby里,require两次,代码也是只执行一次的吧。所以,你上面那个是load的语义。require是没被require过会去load一下。而load必须得eval,因为直接访问的namespace对于所有文件来说是一样的。

#13楼 @bhuztez Ruby里的namespace是自己管理的,所以可能存在冲突,最近还看到这里有一个帖子就是说的namespace冲突的问题

#14楼 @hooopo 我的意思就是说Python的importer可以跳过eval,直接返回结果。module可以随便建的。

比如像下面这样的伪码。

module = new_module()
module['a'] = 1
module['b'] = 2
sys.modules['xxx'] = module

Python的importer机制对Ruby实现类似机制的参考意义并不大。

Perl那个才和Ruby比较接近。

http://perldoc.perl.org/functions/require.html

但Ruby又不一样,Ruby还可以reopen class啊。所以问题就来了,无论如何都要eval一次,importer应该返回,源代码,还是ast,还是bytecode?但是无论返回哪一种,像bitey那样的功能该怎么实现?

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册