【发布时间】:2015-02-15 11:52:03
【问题描述】:
我有一个文件 utils.py,其中包含一个名为 f1() 的函数。
通过另一个 Python 脚本,我可以通过 import utils 或 execfile('utils.py') 访问 f1()。这两种方法有什么区别?
【问题讨论】:
标签: python-2.7 import python-import execfile
我有一个文件 utils.py,其中包含一个名为 f1() 的函数。
通过另一个 Python 脚本,我可以通过 import utils 或 execfile('utils.py') 访问 f1()。这两种方法有什么区别?
【问题讨论】:
标签: python-2.7 import python-import execfile
有许多不同之处,但从您的角度来看,最重要的可能是import 让您可以更好地控制utils.py 中定义的对象最终所在的命名空间。
让我们考虑import 的三个变体。第一个是你问的那个:
import utils
utils.f1()
utils 是唯一添加到您的工作区的符号 - 基本工作区中任何预先存在的 f1 都不会被覆盖,如果没有,那么 f1() 本身不会被覆盖得到认可。对于我打算维护的代码,我非常喜欢这种导入方式,因为它使我可以轻松地搜索我的源文件以查找它依赖于utils 的所有位置。
但如果每次都说utils.f1() 太冗长,那么你可以这样做:
from utils import f1
f1()
现在,如果您说f1(),它将调用utils.f1(),因为这是您现在与工作区中的名称f1 相关联的代码对象。现在要大致了解您的代码在哪里依赖于 utils 模块变得稍微困难一些。但至少这种类型的import 语句可以让您精确控制导入哪些符号,哪些不导入。您甚至可以在此过程中重命名符号:
from utils import f1 as EffOne
EffOne()
最后你可以选择完全失去对命名空间的控制:
from utils import *
现在,谁知道导入了哪些符号:基本上是 utils 必须提供给世界的所有东西(或者,如果 utils 开发人员不厌其烦地指定了 __all__ 属性,那么这里列出的所有东西)。我建议您仅将import * 用于快速而肮脏的编程,如果有的话。
从命名空间的角度来看,这实际上是最接近execfile 的导入样式:execfile('utils.py') 与from utils import * 的作用非常相似,因为它将utils willy-nilly 定义的所有符号转储到您的工作区。一个细微的区别是,execfile 甚至不会将自己限制在 __all__ 中的符号(如果已定义)——事实上,__all__ 符号本身只会与其他所有东西一起被丢在你的腿上。
除了命名空间之外,from utils import * 和 execfile('utils.py') 之间还有很多不同之处。一个是缓存:对utils 的第二次import 调用将非常快(代码不会重新运行),但是对execfile('utils.py') 的第二次调用可能与第一次调用一样长,因为代码 将重新运行。此外,utils.py 中可能有一些代码(通常是测试代码)utils 作者不想在导入时运行,但仅在通过execfile 执行文件时运行。这样的代码放在if __name__ == '__main__': 子句中。
【讨论】:
execfile 已死——exec(open('utils.py').read()) 和 IPython 的 %run utils 万岁。 stackoverflow.com/q/436198