文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Importing Python Mod

2023-01-31 01:36

关注
原文:http://effbot.org/zone/import-confusion.htm

简介

import 和 from-import 对于Python新手经常带来严重的混淆,不过相信大家一旦清楚它们的实现机理后就不会对使用他们有任何困惑了。
这篇文章将努力理清import和from-import 相关的一切。

import modules的几种方式

Python提供至少三种方式来import modules。使用import、from或者内置的__import__function,篇幅所限本文不讨论其他的非主流方式。
下面是这几种方式的实现原理:
  • import X 导入module X,并且在当前命名空间创建到X的引用。换言之,import X后就可以使用X.name使用模块X中的东东了。
  • from X import * 导入module X,并且在当前命名空间创建到X中所有public对象(即除去名称以"_”开头的所有对象)的引用。亦即执行这条语句后,可以直接使用名字使用module X中的东西。但是因为X自身是未定义的,所以无法使用X.name。命名重复时会使用较新的版本,如果X中该名称已经指向其他对象你的模块也不会察觉。这也是该方法的危险之处,虽然用起来方便但容易不知觉间产生BUG。
  • from X import a, b, c 导入module X,并且在当前命名空间创建给定对象的引用,现在可以直接使用a、b和c了。
  • X = __import__(‘X’) 与import X比较相似,不同之处在于:1)可以使用一个string传递module的名字 2)可在当前命名空间将其赋值给一个变量(这在导入的module名称不确定或希望动态导入module时非常有用)

应该采用哪一种?

简而言之:尽量用import。
以下几处情形例外:
  • Module文档要求使用from-import。常见的例子是Tkinter,其被设计为仅向当前命名空间添加widget classes和相关的常量。如果使用import Tkinter会使你的代码可读性很差,故通常不推荐这样做。
  • 导入一个包中的组件。当只需要导入包中一个特定的子module时,使用from io.drivers import zip通常要比import io.drivers.zip方便一些,因为前者可以让我们简单地用zip就可以使用这个module,而不是使用它的全名io.drivers.zip。在这种情况下,from-import起到的作用很像简化的import,而且没有什么命名混淆的风险。
  • 在执行前不清楚module的名字。在这种情况下应该使用__import__(module_name),其中module_name是Python string,这样可以在变更module名称时不需要改动代码。
  • 对自己将做什么非常清楚。如果确认如此那尽可以去用from import,但是一定要三思而后行;-)

Python是如何导入module的?

当Python导入module时,它首先检查module注册表(sys.modules)确认是否该module已经被导入过,如果存在就使用已导入的module代替它。
否则,Python将执行以下步骤:
  1. 创建一个新的空module对象(其本质是一个dictionary)
  2. 将该module对象插入到sys.modules dictionary中
  3. 加载module的代码对象(如果需要会先编译这个module)
  4. 在新module的命名空间执行该module的代码对象,代码中赋值的所有变量在该module对象里可用。通过该module对象中Execute the module code object in the new module’s namespace. All variables assigned by the code will be available via the module object.
这意味着导入一个已经加载的module性能消耗是非常小的,Python只需要在dictionary中查找下module的名字就可以了。

其他要点

使用module作为脚本

如果你将一个module作为脚本运行,即直接将其名称给编译器而非导入它,那它将以名称__main__加载。
如果稍后在程序中加载同一个module,它将被重新加载并以其真实的名称重新执行,所以如果不细心的话可能会做两次同样的事。

循环导入

在Python中,像def、class和import之类的语句都是声明。
module在导入时被执行,但新的函数和类并不会添加到module的命名空间中直到执行def或class进行声明,这在循环导入会有很明显的影响。
比如module X导入module Y并定义一个函数spam:
    # module X
    import Y
    def spam():
        print "function in module x"
如果从主程序中导入X,Python将加载X的代码并执行它。当Python到import Y这一行声明时,它加载Y的代码并转而执行Y的代码。
此时,Python已经在sys.modules中加载了X和Y。但X还不包含任何东西,def spam这行声明还未执行。
现在如果Y导入X(出现循环导入),它将得到一个指向空module X对象的引用,但如果试图调用函数X.spam将会失败,因为此时虽然存在X但并不存在X.spam:
    # module Y
    from X import spam # doesn't work: spam isn't defined yet!
这个问题和使用from-import无关,即使换用import也会如此:
    # module Y
    import X
    X.spam() # doesn't work either: spam isn't defined yet!
解决的方法就是重构代码来避免循环导入,通常可以通过将部分内容拆分到单独的module来解决。这种解决方式类似于C++中解决循环引用时使用前置声明将声明和定义分离的方法,即将冲突的执行代码分拆到其他文件。
或者将import移到module的末尾,比如上面的例子如果将import Y移到module X的末尾就可以一切正常了,但其实并不总奏效,万一X.spam使用过Y就又出错了。
阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯