python之from 和import执行过程分析
原文链接:https://www.geek-share.com/detail/2688034727.html
问题1
同一个目录下,有两个Python文件,A.py,B.py
#A.py from B import D class C(object): pass #B.py from A import C class D(object): pass ''' 执行A.py 结果: Traceback (most recent call last): File "A.py", line 4, in <module> from B import D File "B.py", line 4, in <module> from A import C File "A.py", line 4, in <module> from B import D ImportError: cannot import name D '''
why?
from B import D的执行机制
可以利用sys.modules查看是否包含B模块,如查看os模块,输入
>>> sys.modules[‘os’].
-
存在模块B
如果sys.modules有B这个键,就会获取相对应的值,也就是modules对象,然后从模块B的__dict__列表中查找并获取名称为D的对象,如果不存在,抛出异常.
模块B的__dict__列表可利用dir(B)来查看.
-
不存在模块B
如果不存在B这个键的话,则会为B创建一个模块对象,此时模块对象的__dict__列表为空,然后在搜索路径下查找并执行B.py,以填充模块B对象的__dict__列表,然后从__dict__列表中查找名称为D的对象,如果找不到,则抛出异常.
注:module ,模块的意思
根据上面修改代码,查看sys.modules变化情况
#A.py #!/usr/bin/python # -*- coding: utf-8 -*- import sys try: print 'module B: %s'%sys.modules['B'] except Exception,e: print u'没有module B %s'%e try: print 'module A: %s'%sys.modules['A'] except Exception,e: print u'没有module A %s'%e from B import D class C(object): pass #B.py from A import C class D(object): pass ''' 执行A.py 结果: 没有module B 'B' 没有module A 'A' module B: <module 'B' from 'B.pyc'> module A: <module 'A' from 'A.py'> Traceback (most recent call last): File "A.py", line 4, in <module> from B import D File "B.py", line 4, in <module> from A import C File "A.py", line 4, in <module> from B import D ImportError: cannot import name D
问题1答案
- 运行A.py,当执行到from B import D语句时,因为还没有运行过B.py,所以sys.modules中没有B这个键.会创建一个键B并赋值为模块B对象,只不过此时模块B对象是空的,里面什么都没有;
- 然后,暂停执行A.py的其他语句,Python 在搜索路径下查找B.py,找到同目录下的B.py并运行,为了填充模块B对象中的__dict__列表.当执行到from A import C时,也会检查sys.modules中是否有名为A的模块,但因为A.py还没有读取完,所以并没有在sys.modules中缓存对应的信息.同样,Python 会创建一个键A并赋值为空的模块A对象.暂停执行B.py并寻找、从头执行A.py.
- 这时,会再次执行到from B import D语句,由于在第一步时已经在sys.modules创建了键B的模块B对象,所以直接获取到,但此时模块B对象中的__dict__列表还是空的,里面什么都没有啊,所以找不到名为D的对象,抛出异常.
对照运行结果,是不是很符合- -!
(表述能力有限,多看代码吧- -)
问题2 将上述from import 换成 import
#A1.py #!/usr/bin/python # -*- coding: utf-8 -*- import sys try: print 'module B1: %s'%sys.modules['B1'] except Exception,e: print u'没有module B1 %s'%e try: print 'module A1: %s'%sys.modules['A1'] except Exception,e: print u'没有module A1 %s'%e import B1 class C(object): pass try: B1.D() except Exception,e: print u'B中没有属性D',e #B1.py import A1 class D(object): pass ''' 执行A.py 结果: 没有module B1 'B1' 没有module A1 'A1' module B1: <module 'B1' from 'B1.pyc'> module A1: <module 'A1' from 'A1.py'> B中没有属性D 'module' object has no attribute 'D' '''
由程序结果可知,将from…import…改成import后,程序不会出错了,但是调用B1.D()时为什么会抛出异常呢?
问题2答案
-
运行A1.py,当执行到import B1语句时,因为还没有运行过B1.py,所以sys.modules中没有B1这个键.会创建一个键B1并赋值为模块B1对象,只不过此时这个模块对象是空的,里面什么都没有;
-
然后,暂停执行A1.py的其他语句,Python 在搜索路径下查找B1.py,找到同目录下的B1.py并运行,为了填充模块B1对象中的__dict__列表.当执行到import A1时,也会检查sys.modules中是否有名为A1的模块,但因为A1.py还没有读取完,所以并没有在sys.modules中缓存对应的信息.然后,同样的,Python 会创建一个键A1并赋值为空的模块A1对象.暂停执行B1.py并寻找、从头执行A1.py.
-
这时,会再次执行到import B1语句,由于在第一步时已经在sys.modules创建了模块B1对象,模块B1对象已经存在了,不需要执行B1.py,所以继续执行A1.py中的其他内容.
注意:此时模块B1仍为空的,里面什么都没有.
-
当执行到B1.D()时,由于在模块B1对象的__dict__列表找不到名为D的对象,抛出异常.
问题3 修改问题1中的程序使的能正确运行
#A2.py from B2 import D class C(object): pass #B2.py class D(object): pass from A2 import C
简单说明:
A2.py->B2.py->A2.py时,D属性已经在B2的__dict__列表中了,所以不会报错…虽然这样写不会报错,但是强烈不推荐这么写….
总结
当Python程序导入其他模块时,要避免循环导入,不然总会出意向不到的问题….
注:循环导入,即A文件导入了B,B文件又导入了A.
重新导入模块
如果更新了一个已经用import语句导入的模块,内建函数reload()可以重新导入并运行更新后的模块代码.它需要一个模块对象做为参数.例如:
import foo
... some code ...
reload(foo) # 重新导入 foo
在reload()运行之后的针对模块的操作都会使用新导入代码,不过reload()并不会更新使用旧模块创建的对象,因此有可能出现新旧版本对象共存的情况。*注意* 使用C或C++编译的模块不能通过 reload() 函数来重新导入。记住一个原则,除非是在调试和开发过程中,否则不要使用reload()函数
- Mycat之日志分析 select * from travelrecord order by id limit 100000,100 的执行过程
- python import导入模块执行流程分析
- Python装饰器的执行过程实例分析
- 14 Python from-import-执行机制
- Mapreduce执行过程分析(基于Hadoop2.4)——(三)
- Python中import与from……import的使用
- from.....import 与 import 分类: python 2013-03-05 16:50 239人阅读 评论(0) 收藏
- Twitter Storm源代码分析之Topology的执行过程
- Java中for循环的执行过程分析
- Spring Security4.0.3源码分析之FilterChainProxy执行过程分析
- SQL Server 第四堂课,创建存储过程。存储过程是一组编译在单个执行计划中的transact-SQL语句。存储过程相当于C#函数,可以允许模块化程序设计,允许更快执行如果某操作需要大量transct-SQL代码或需要重复执行,将在创建存储过程中对其进行分析和优化。
- Mybatis源码分析之Mapper执行SQL过程(三)
- Android应用程序UI硬件加速渲染的动画执行过程分析
- hive 执行过程源码分析
- python 清晰讲解 from import 和 import
- 实现分析sql语句执行过程和编译时间的方法
- Android系统Recovery工作原理之使用update.zip升级过程分析(九)---updater-script脚本语法简介以及执行流程
- 说说Python程序的执行过程
- openwrt系统 sysupgrade 命令执行过程分析
- Android系统Recovery工作原理之使用update.zip升级过程分析(八)---升级程序update_binary的执行过程