Python Import机制

1. 标准 import
        Python 中所有加载到内存的模块都放在 sys.modules 。当 import一个模块时首先会在这个列表中查找是否已经加载了此模块,如果加载了则只是将模块的名字加入到正在调用 import 的模块的 Local名字空间中。如果没有加载则从 sys.path目录中按照模块名称查找模块文件,模块可以是py、pyc、pyd,找到后将模块载入内存,并加到 sys.modules中,并将名称导入到当前的 Local 名字空间。
        一个模块不会重复载入。多个不同的模块都可以用 import 引入同一个模块到自己的Local 名字空间,其实背后的 PyModuleObject 对象只有一个。说一个容易忽略的问题: import只能导入模块,不能导入模块中的对象(类、函数、变量等)。例如:模块 A(A.py)中有个函数getName,另一个模块不能通过 import A.getName 将 getName导入到本模块,只能用from  A import getName。

2. 嵌套import
     1)顺序嵌套
      例如:本模块导入 A 模块(import A),A 中又import B,B 模块又可以 import 其他模块……
      这中嵌套比较容易理解,需要注意的一点就是各个模块的Local 名字空间是独立的。对于上面的例子,本模块 import A 之后本模块只能访问模块 A,不能访问模块 B及其他模块。虽然模块 B 已经加载到内存了,如果访问还要再明确的在本模块中 import B。
     2)循环嵌套
       例如:文件[ A.py]
                from B importD
                classC:pass

                文件[ B.py ]
                from A importC
                classD:pass
       为什么执行 A的时候不能加载 D 呢?
       如果将 A.py改为:import B 就可以了。
      这是怎么回事呢?

      RobertChen:这跟Python内部 import 的机制是有关的,具体到 from B import D,Python内部会分成几个步骤:
       (1)在sys.modules 中查找符号 “B”
       (2)如果符号 B存在,则获得符号 B 对应的 module 对象。
             从 <modult B> 的__dict__ 中获得符号 “D” 对应的对象,如果 “D” 不存在,则抛出异常。
       (3)如果符号 B不存在,则创建一个新的 module 对象 <moduleB>,注意,此时,module 对象的 __dict__ 为空。
             执行 B.py中的表达式,填充  <moduleB>  的 __dict__。
             从    <moduleB>  的 __dict__ 中获得 “D” 对应的对象,如果“D” 不存在,则抛出异常。

        所以这个例子的执行顺序如下:
        1、执行 A.py 中的 from Bimport D 由于是执行的 python A.py,所以在 sys.modules 中并没有<module B> 存在, 首先为 B.py 创建一个 module对象 (<module B>) , 注意,这时创建的这个 module对象是空的,里边啥也没有, 在 Python 内部创建了这个 module 对象之后,就会解析执行 B.py,其目的是填充<module B> 这个__dict__。 
          2、执行 B.py中的from A import C在执行B.py的过程中,会碰到这一句,首先检查sys.modules这个module缓存中是否已经存在<moduleA>了, 由于这时缓存还没有缓存<moduleA>,所以类似的,Python内部会为A.py创建一个module对象(<moduleA>), 然后,同样地,执行A.py中的语句
 
        3、再次执行A.py中的from B import D这时,由于在第1步时,创建的<moduleB>对象已经缓存在了sys.modules中,所以直接就得到了<module B>,但是,注意,从整个过程来看,我们知道,这时<moduleB>还是一个空的对象,里面啥也没有, 所以从这个module中获得符号"D"的操作就会抛出异常。如果这里只是import B,由于"B"这个符号在sys.modules中已经存在,所以是不会抛出异常的。
ZQ:图解
python之import机制
啄木鸟社区《import 迷宫》: http://wiki.woodpecker.org.cn/moin/MiscItems/2008-11-25

3. 包 import
            只要一个文件夹下面有个 __init__.py文件,那么这个文件夹就可以看做是一个包。包导入的过程和模块的基本一致,只是导入包的时候会执行此包目录下的 __init__.py 而不是模块里面的语句了。另外,如果只是单纯的导入包,而包的__init__.py 中又没有明确的其他初始化操作,那么此包下面的模块是不会自动导入的。
       例如:
               有下面的包结构:
               
PA
               |---- __init__.py
               |---- wave.py
               |---- PB1
                     |---- __init__.py
                    |---- pb1_m.py
              |---- PB2
                     |---- __init__.py
                     |---- pb2_m.py

               有如下程序:
                              import sys
                              import PA.wave                             #1
                              import PA.PB1                               #2
                              import PA.PB1.pb1_m as m1         #3
                              import PA.PB2.pb2_m                   #4
                             
                              PA.wave.getName()                      #5
                              m1.getName()                               #6
                              PA.PB.pb2_m.getName()               #7

              1) 当执行 #1 后,sys.modules 会同时存在PA、PA.wave 两个模块,此时可以调用 PA.wave 的任何类或函数了。但不能调用 PA.PB1(2) 下的任何模块。当前Local 中有了 PA 名字。
              2) 当执行 #2 后,只是将 PA.PB1载入内存,sys.modules 中会有 PA、 PA.wave、PA.PB1 三个模块,但是 PA.PB1下的任何模块都没有自动载入内存,此时如果直接执行 PA.PB1.pb1_m.getName() 则会出错,因为 PA.PB1 中并没有pb1_m 。当前 Local 中还是只有 PA 名字,并没有 PA.PB1 名 字。
              3) 当执行 #3 后,会将 PA.PB1 下的pb1_m 载入内存,sys.modules 中会有 PA、PA.wave、PA.PB1、PA.PB1.pb1_m四个模块,此时可以执行 PA.PB1.pb1_m.getName() 了。由于使用了 as,当前 Local中除了 PA名字,另外添加了 m1 作为 PA.PB1.pb1_m 的别名。
              4) 当执行 #4 后,会将PA.PB2、PA.PB2.pb2_m 载入内存,sys.modules 中会有PA、PA.wave、PA.PB1、PA.PB1.pb1_m、PA.PB2、PA.PB2.pb2_m 六个模块。当前 Local中还是只有 PA、m1。
               下面的 #5,#6,#7 都是可以正确运行的。
               注意的是:如果 PA.PB2.pb2_m 想导入 PA.PB1.pb1_m、PA.wave是可以直接成功的。最好是采用明确的导入路径,对于 ./.. 相对导入路径还是不推荐用。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,为适合; 4、下载使用后,可先查看REaDME.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 、资源1项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值