从Python调用Python - 模块导入的持久性?
我有一些Python脚本,并且我用BaseHTTPServer来提供它们的响应。如果请求的文件是.py格式的,我会用execfile(script.py)来运行这个脚本。
我的问题是:关于导入模块有没有什么特别的规则?有一个脚本只需要运行一次,最好能让它创建的对象在请求之间保持活跃。我能相信这会发生吗?
通过execfile()运行的脚本会有什么不同,或者会有作用域访问的问题吗?
2 个回答
我建议不要使用 execfile
。相反,你可以使用内置的 __import__
函数动态地将用户请求的 Python 文件作为模块导入。下面是我刚写并测试过的一个完整示例:
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header("Content-type", "text/plain")
self.end_headers()
filename = self.path.lstrip("/")
self.wfile.write("You requested " + filename + "\n\n")
if filename.endswith(".py"):
pyname = filename.replace("/", ".")[:-3]
module = __import__(pyname)
self.wfile.write( module.do_work() )
HTTPServer(("",8080), Handler).serve_forever()
在这个例子中,如果有人访问 http://localhost:8080/some_page,那么页面上会显示“You requested some_page”。
但是如果你请求 http://localhost:8080/some_module.py,那么文件 some_module.py
会作为一个 Python 模块被导入,并且会调用该模块中的 do_work
函数。所以如果这个模块包含以下代码:
def do_work():
return "Hello World!"
然后你发出这个请求,结果页面将会是:
You requested some_module.py
Hello World!
这应该是处理这类事情的一个不错的起点。顺便提一下,如果你想要一个更高级的网络服务器,我强烈推荐 CherryPy。
关于execfile这个方法的说明可以在这里找到。因为没有特别指定Python的版本,我假设我们讨论的是2.6.2版本。
execfile的说明里提到,它需要三个参数:文件名、一个字典(用作局部变量)和第二个字典(用作全局变量)。如果你不提供第二个和第三个参数,那么文件里的内容会在自己的作用域中运行(就像一个模块),这个作用域可以捕捉局部变量,但全局变量会暴露给父作用域。所以,如果文件创建了局部变量,这些变量不会被保留,但全局变量会被保留。
不过,如果在没有指定局部和全局上下文的情况下运行execfile,文件就能看到调用函数的局部和全局变量。对于你不信任的代码,这可能会带来安全隐患。通常来说,创建两个字典来分别存储局部和全局变量,并将它们作为第二和第三个参数传给execfile是个明智的选择。如果你把这些字典放在某个地方(比如用文件名作为键的另一个字典里),那么下次使用这个文件时就可以重用这些字典,这样文件创建的对象就能保持活跃。
简单来说:execfile和import不完全一样。但是你可以保留局部和全局的字典,以便再次使用execfile调用的结果。