python之from 和import执行过程分析

原文链接:http://blog.csdn.net/lis_12/article/details/52883729

问题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’].

  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 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答案

  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 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答案

  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.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()函数

原文地址:https://www.cnblogs.com/lfxiao/p/9295672.html

时间: 2024-07-31 23:09:06

python之from 和import执行过程分析的相关文章

Mapreduce执行过程分析(基于Hadoop2.4)——(一)

1 概述 该瞅瞅MapReduce的内部运行原理了,以前只知道个皮毛,再不搞搞,不然怎么死的都不晓得.下文会以2.4版本中的WordCount这个经典例子作为分析的切入点,一步步来看里面到底是个什么情况. 2 为什么要使用MapReduce Map/Reduce,是一种模式,适合解决并行计算的问题,比如TopN.贝叶斯分类等.注意,是并行计算,而非迭代计算,像涉及到层次聚类的问题就不太适合了. 从名字可以看出,这种模式有两个步骤,Map和Reduce.Map即数据的映射,用于把一组键值对映射成另

Python中直接在MySQL执行SQL命令

因为懒,所以不想用SQLyog,用Python写了一个快速执行SQL命令的程序: import pymysql,sys class dealMySQL(object):     'PyMysql'     version = 'Version:0.1'      author = 'Author: August'          def __init__(self):         pass          @classmethod         def execute(self,sql

python程序在命令行执行提示ModuleNotFoundError: No module named &#39;XXX&#39; 解决方法

原文链接:https://www.cnblogs.com/dreamyu/p/7889959.html 在ide中执行python程序,都已经在默认的项目路径中,所以直接执行是没有问题的.但是在cmd中执行程序,所在路径是python的搜索路径,如果涉及到import引用就会报类似ImportError: No module named xxx这样的错误,解决方法: 在报错的模块中添加: import sys import os curPath = os.path.abspath(os.path

Mapreduce执行过程分析(基于Hadoop2.4)——(三)

4.4 Reduce类 4.4.1 Reduce介绍 整完了Map,接下来就是Reduce了.YarnChild.main()—>ReduceTask.run().ReduceTask.run方法开始和MapTask类似,包括initialize()初始化,根据情况看是否调用runJobCleanupTask(),runTaskCleanupTask()等.之后进入正式的工作,主要有这么三个步骤:Copy.Sort.Reduce. 4.4.2 Copy Copy就是从执行各个Map任务的节点获取

Mapreduce执行过程分析(基于Hadoop2.4)——(二)

4.3 Map类 创建Map类和map函数,map函数是org.apache.hadoop.mapreduce.Mapper类中的定义的,当处理每一个键值对的时候,都要调用一次map方法,用户需要覆写此方法.此外还有setup方法和cleanup方法.map方法是当map任务开始运行的时候调用一次,cleanup方法是整个map任务结束的时候运行一次. 4.3.1 Map介绍 Mapper类是一个泛型类,带有4个参数(输入的键,输入的值,输出的键,输出的值).在这里输入的键为Object(默认是

图库Gallery3D(Gallery2)分析(四) 菜单命令执行过程分析

该分析基于 Android4.2的Gallery2 1 菜单创建过程分析. Gallery的父类是AbstractGalleryActivity类,AbstractGalleryActivity的父类是Activity类.所以菜单创建是调用的AbstractGalleryActivity的菜单创建函数. public class AbstractGalleryActivity extends Activity implements GalleryContext { private static

Task的执行过程分析

Task的执行过程分析 Task的执行通过Worker启动时生成的Executor实例进行, caseRegisteredExecutor(sparkProperties)=> logInfo("Successfullyregistered with driver") //Make this host instead of hostPort ? executor= newExecutor(executorId, Utils.parseHostPort(hostPort)._1,s

ART运行时Semi-Space(SS)和Generational Semi-Space(GSS)GC执行过程分析

Semi-Space(SS)GC和Generational Semi-Space(GSS)GC是ART运行时引进的两个Compacting GC.它们的共同特点是都具有一个From Space和一个To Space.在GC执行期间,在From Space分配的还存活的对象会被依次拷贝到To Space中,这样就可以达到消除内存碎片的目的.本文就将SS GC和GSS GC的执行过程分析进行详细分析. 老罗的新浪微博:http://weibo.com/shengyangluo,欢迎关注! 与SS G

MFC的执行过程分析

MFC程序的执行细节剖析 MFC程序也是Windows程序,所以它应该也有一个WinMain.可是在程序中看不到它的踪影.事实上在程序进入点之前.另一个(并且仅有一个)全局对象(theApp).这就是所谓的Application object,当操作系统将程序载入并激活时,这个全局对象获得配置,其构造函数会先运行.比WinMain更早. 一 CWinApp代替WinMain CWinApp的派生对象被称为application object,能够想见,CWinApp本身就代表一个程序本体.所谓程