博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
python之from 和import执行过程分析
阅读量:5291 次
发布时间:2019-06-14

本文共 3654 字,大约阅读时间需要 12 分钟。

原文链接:

问题1

同一个目录下,有两个Python文件,A.py,B.py

#A.pyfrom B import Dclass C(object):    pass#B.pyfrom A import Cclass D(object):    pass'''执行A.py结果:Traceback (most recent call last):  File "A.py", line 4, in 
from B import D File "B.py", line 4, in
from A import C File "A.py", line 4, in
from B import DImportError: cannot import name D'''

 

why?

from B import D的执行机制

可以利用sys.modules查看是否包含B模块,如查看os模块,输入

>>> sys.modules[‘os’].

  1. 存在模块B

    如果sys.modules有B这个键,就会获取相对应的值,也就是modules对象,然后从模块B的__dict__列表中查找并获取名称为D的对象,如果不存在,抛出异常.

    模块B的__dict__列表可利用dir(B)来查看.

  2. 不存在模块B

    如果不存在B这个键的话,则会为B创建一个模块对象,此时模块对象的__dict__列表为空,然后在搜索路径下查找并执行B.py,以填充模块B对象的__dict__列表,然后从__dict__列表中查找名称为D的对象,如果找不到,则抛出异常.

    注:module ,模块的意思

 

根据上面修改代码,查看sys.modules变化情况

#A.py#!/usr/bin/python# -*- coding: utf-8 -*-import systry:    print 'module B: %s'%sys.modules['B']except Exception,e:    print u'没有module B  %s'%etry:    print 'module A: %s'%sys.modules['A']except Exception,e:    print u'没有module A  %s'%efrom B import Dclass C(object):    pass#B.pyfrom A import Cclass D(object):    pass'''执行A.py结果:没有module B  'B'没有module A  'A'module B: 
module A:
Traceback (most recent call last): File "A.py", line 4, in
from B import D File "B.py", line 4, in
from A import C File "A.py", line 4, in
from B import DImportError: cannot import name D

问题1答案

  1. 运行A.py,当执行到from B import D语句时,因为还没有运行过B.py,所以sys.modules中没有B这个键.会创建一个键B并赋值为模块B对象,只不过此时模块B对象是空的,里面什么都没有;
  2. 然后,暂停执行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.
  3. 这时,会再次执行到from B import D语句,由于在第一步时已经在sys.modules创建了键B的模块B对象,所以直接获取到,但此时模块B对象中的__dict__列表还是空的,里面什么都没有啊,所以找不到名为D的对象,抛出异常.

对照运行结果,是不是很符合- -!

(表述能力有限,多看代码吧- -)

问题2 将上述from import 换成 import

#A1.py#!/usr/bin/python# -*- coding: utf-8 -*-import systry:    print 'module B1: %s'%sys.modules['B1']except Exception,e:    print u'没有module B1 %s'%etry:    print 'module A1: %s'%sys.modules['A1']except Exception,e:    print u'没有module A1 %s'%eimport B1class C(object):    passtry:    B1.D()except Exception,e:    print u'B中没有属性D',e#B1.pyimport A1class D(object):    pass'''执行A.py结果:没有module B1 'B1'没有module A1 'A1'module B1: 
module A1:
B中没有属性D 'module' object has no attribute 'D''''

由程序结果可知,将from…import…改成import后,程序不会出错了,但是调用B1.D()时为什么会抛出异常呢?

问题2答案

  1. 运行A1.py,当执行到import B1语句时,因为还没有运行过B1.py,所以sys.modules中没有B1这个键.会创建一个键B1并赋值为模块B1对象,只不过此时这个模块对象是空的,里面什么都没有;

  2. 然后,暂停执行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.

  3. 这时,会再次执行到import B1语句,由于在第一步时已经在sys.modules创建了模块B1对象,模块B1对象已经存在了,不需要执行B1.py,所以继续执行A1.py中的其他内容.

    注意:此时模块B1仍为空的,里面什么都没有.

  4. 当执行到B1.D()时,由于在模块B1对象的__dict__列表找不到名为D的对象,抛出异常.

问题3 修改问题1中的程序使的能正确运行

#A2.pyfrom B2 import Dclass C(object):    pass#B2.pyclass D(object):    passfrom 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()函数

 

转载于:https://www.cnblogs.com/lfxiao/p/9295672.html

你可能感兴趣的文章
Servlet3.0新特性
查看>>
java内存溢出怎么解决
查看>>
JS对象以及"继承"
查看>>
Ewebeditor最新漏洞及漏洞大全
查看>>
socket计划编制的原则
查看>>
sqlite3经常使用命令&语法
查看>>
[leetcode] 309. Best Time to Buy and Sell Stock with Cooldown(medium)
查看>>
解决微信授权回调页面域名只能设置一个的问题 [php]
查看>>
数组去重一步到位
查看>>
HDU 4671 Backup Plan 构造
查看>>
linux下编译openjdk8
查看>>
【python】--迭代器生成器装饰器
查看>>
Pow(x, n)
查看>>
安卓当中的线程和每秒刷一次
查看>>
MySQL Proxy
查看>>
关于Vue的组件的通用性问题
查看>>
随机颜色值
查看>>
每日一库:Modernizr.js,es5-shim.js,es5-safe.js
查看>>
目录相关的操作
查看>>
解决虚拟机vmware安装64位系统“此主机支持 Intel VT-x,但 Intel VT-x 处于禁用状态”的问题...
查看>>