import_important - CSDN
精华内容
参与话题
  • python中的import详解

    万次阅读 2013-03-17 17:25:03
    import 一个模块时首先会在这个列表中查找是否已经加载了此模块: 如果加载了则只是将模块的名字加入到正在调用 import 的模块的 Local 名字空间中。 如果没有加载则从 sys.path 目录中按照模块名称查找模块...

    标准的导入模块

    在python中所有加载到内存中的模块都存在于sys.modules

    当 import 一个模块时首先会在这个列表中查找是否已经加载了此模块:

    如果加载了则只是将模块的名字加入到正在调用 import 的模块的 Local 名字空间中。

    如果没有加载则从 sys.path 目录中按照模块名称查找模块文件,模块可以是py、pyc、pyd,找到后将模块载入内存,并加到 sys.modules 中,

    并将名称导入到当前的 Local名字空间
    一个模块不会重复载入。多个不同的模块都可以用 import 引入同一个模块到自己的 Local 名字空间,其实背后的 PyModuleObject 对象只有一个。

    注意

    • import导入为绝对导入
    • import 只能导入模块,不能导入模块中的对象(类、函数、变量等)

     

    嵌套import

    顺序嵌套

    例如:本模块导入 A 模块(import A),A 中又 import B,B 模块又可以 import 其他模块……
    注意:各个模块的 Local 名字空间是独立的

    对于上面的例子,本模块 import A 之后本模块只能访问模块 A,不能访问模块 B 及其他模块。虽然模块 B 已经加载到内存了,如果访问还要再明确的在本模块中 import B。

    循环嵌套

    例如:文件[ A.py ]
                       from B import D
                       class C:pass


                       文件[ B.py ]
                       from A import C
                       class D: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 对象 <module B>,注意,此时,module 对象的 __dict__ 为空。
                    执行 B.py 中的表达式,填充 <module B> 的 __dict__。
                    从  <module B> 的 __dict__ 中获得 “D” 对应的对象,如果 “D” 不存在,则抛出异常。


              所以这个例子的执行顺序如下:
              1、执行 A.py 中的 from B import 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缓存中是否已经存在<module A>了, 由于这时缓存还没有缓存<module A>,所以类似的,Python内部会为A.py创建一个module对象(<module A>), 然后,同样地,执行A.py中的语句
              3、再次执行A.py中的from B import D 这时,由于在第1步时,创建的<module B>对象已经缓存在了sys.modules中,所以直接就得到了<module B>,但是,注意,从整个过程来看,我们知道,这时<module B>还是一个空的对象,里面啥也没有, 所以从这个module中获得符号"D"的操作就会抛出异常。如果这里只是import B,由于"B"这个符号在sys.modules中已经存在,所以是不会抛出异常的。

    包 import

           只要一个文件夹下面有个 __init__.py 文件,那么这个文件夹就可以看做是一个包

    包导入的过程和模块的基本一致,只是导入包的时候会执行此包目录下的 __init__.py 而不是模块里面的语句了。

    如果只是单纯的导入包,而包的 __init__.py 中又没有明确的其他初始化操作,那么此包下面的模块是不会自动导入的

    原文地址:http://blog.sina.com.cn/s/blog_90bc5fc6010159e0.html
    展开全文
  • java中import作用详解

    万次阅读 多人点赞 2017-07-10 08:55:30
    java中import详解import与package机制相关,这里先从package入手,再讲述import以及static import的作用。

    import与package机制相关,这里先从package入手,再讲述import以及static import的作用。


    package

    C/C++ 的 #include会把所包含的内容在编译时添加到程序文件中,而java的import则不同。

    这里我们先了解一下Java 的 package 到底有何用处。

    package名称就像是我们的姓,而class名称就像是我们的名字 。package和package的附属关系用”.”来连接,这就像是复姓。比如说 java.lang.String就是复姓 java.lang,名字為 String 的类别;java.io.InputStream 则是复姓 java.io,名字為 InputStream的类别。

    Java 会使用 package 这种机制的原因也非常明显,就像我们取姓名一样 ,光是一间学校的同一届同学中,就有可能会出现不少同名的同学,如果不取姓的话,那学校在处理学生资料,或是同学彼此之间的称呼,就会发生很大的困扰。相同的,全世界的 Java 类数量,恐怕比日本人还多,如果类别不使用package名称,那在用到相同名称的不同类时, 就会产生极大的困扰。所以package这种方式让极大降低了类之间的命名冲突。

    Java 的package名称我们可以自己取,不像人的姓没有太大的选择 ( 所以出现很多同名同姓的情况 ),如果依照 Sun 的规范来取套件名称,那理论上不同人所取的套件名称不会相同 ( 需要的话请参阅 “命名惯例” 的相关文章 ),也就不会发生名称冲突的情况。

    可是现在问题来了,因為很多package的名称非常的长,在编程时,要使用一个类要将多个包名.类名完全写出,会让代码变得冗长,减低了简洁度。例如

    java.io.InputStream is = java.lang.System.in;
    java.io.InputStreamReader isr= new java.io.InputStreamReader(is);
    java.io.BufferedReader br = new java.io.BufferedReader(isr);

    显得非常麻烦,于是Sun公司就引入了import。


    import

    import就是在java文件开头的地方,先说明会用到那些类别。
    接着我们就能在代码中只用类名指定某个类,也就是只称呼名字,不称呼他的姓。

    首先,在程序开头写:

    import java.lang.System;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.BufferedReader;

    于是我们就可以在程序中这样写到:

    InputStream = System.in;
    InputStreamReader isr = new InputStreamReader(is);
    BufferedReader br = new BufferedReader(isr);

    一个java文件就像一个大房间,我们在门口写着在房间里面的class的姓和名字,所以在房间里面提到某个class就直接用他的名字就可以。例如:

    System 就是指 java.lang.System,而 InputStream 就是指 java.io.InputStream。

    但是如果一个java文件里面有多个同个“姓”,即包名相同的类(例如上面的InputStream,InputStreamReader,BufferedReader都是java.io中的类),我们一一写出显得比较繁杂,所以Sun就让我们可以使用

    import java.lang.*;
    import java.io.*;

    表示文件里面说到的类不是java.lang包的就是java.io包的。编译器会帮我们选择与类名对应的包。

    那我们可不可以再懒一点直接写成下面声明呢?

    import java.*;

    历史告诉我们,这样是不行的。因為那些类别是姓 java.io 而不是姓 java。就像姓『诸葛』的人应该不会喜欢你称他為『诸』 先生吧。这样写的话只会将java包下的类声明,而不不会声明子包的任何类。

    这里注意,java.lang包里面的类实在是太常太常太常用到了,几乎没有类不用它的, 所以不管你有没有写 import java.lang,编译器都会自动帮你补上,也就是说编译器只要看到没有姓的类别,它就会自动去lang包里面查找。所以我们就不用特别去 import java.lang了。

    一开始说 import 跟 #include 不同,是因为import 的功能到此為止,它不像#include 一样,会将其他java文件的内容载入进来。import 只是让编译器编译这个java文件时把没有姓的类别加上姓,并不会把别的文件程序写进来。你开心的话可以不使用import,只要在用到类别的时候,用它的全部姓名来称呼它就行了(就像例子一开始那样),这样跟使用import功能完全一样。


    import的两种导入声明

    • 单类型导入(single-type-import)
      (例:import java.util.ArrayList; )
    • 按需类型导入(type-import-on-demand)
      (例:import java.util.*;)

    有如下属性:

    1. java以这样两种方式导入包中的任何一个public的类和接口(只有public类和接口才能被导入)

    2. 上面说到导入声明仅导入声明目录下面的类而不导入子包,这也是为什么称它们为类型导入声明的原因。

    3. 导入的类或接口的简名(simple name)具有编译单元作用域。这表示该类型简名可以在导入语句所在的编译单元的任何地方使用.这并不意味着你可以使用该类型所有成员的简名,而只能使用类型自身的简名。
      例如: java.lang包中的public类都是自动导入的,包括Math和System类.但是,你不能使用它们的成员的简名PI()和gc(),而必须使用Math.PI()和System.gc().你不需要键入的是java.lang.Math.PI()和java.lang.System.gc()。

    4. 程序员有时会导入当前包或java.lang包,这是不需要的,因为当前包的成员本身就在作用域内,而java.lang包是自动导入的。java编译器会忽略这些冗余导入声明(redundant import declarations)。即使像这样
      import java.util.ArrayList;
      import java.util.*;
      多次导入,也可编译通过。编译器会将冗余导入声明忽略.


    static import静态导入

    在Java程序中,是不允许定义独立的函数和常量的。即什么属性或者方法的使用必须依附于什么东西,例如使用类或接口作为挂靠单位才行(在类里可以挂靠各种成员,而接口里则只能挂靠常量)。

    如果想要直接在程序里面不写出其他类或接口的成员的挂靠单元,有一种变通的做法 :
    将所有的常量都定义到一个接口里面,然后让需要这些常量的类实现这个接口(这样的接口有一个专门的名称,叫(“Constant Interface”)。这个方法可以工作。但是,因为这样一来,就可以从“一个类实现了哪个接口”推断出“这个类需要使用哪些常量”,有“会暴露实现细节”的问题。

    于是J2SE 1.5里引入了“Static Import”机制,借助这一机制,可以用略掉所在的类或接口名的方式,来使用静态成员。static import和import其中一个不一致的地方就是static import导入的是静态成员,而import导入的是类或接口类型

    如下是一个有静态变量和静态方法的类

    package com.assignment.test;
    
    public class staticFieldsClass {
        static int staticNoPublicField = 0; 
        public static int staticField = 1;
        public static void staticFunction(){}
    }

    平时我们使用这些静态成员是用类名.静态成员的形式使用,即staticFieldsClass.staticField或者staticFieldsClass.staticFunction()。

    现在用static import的方式:

    //**精准导入**
    //直接导入具体的静态变量、常量、方法方法,注意导入方法直接写方法名不需要括号。
    import static com.assignment.test.StaticFieldsClass.staticField;
    import static com.assignment.test.StaticFieldsClass.staticFunction;
    
    //或者使用如下形式:
    //**按需导入**不必逐一指出静态成员名称的导入方式
    //import static com.assignment.test.StaticFieldsClass.*;
    
    public class StaticTest {
        public static void main(String[] args) {
            //这里直接写静态成员而不需要通过类名调用
            System.out.println(staticField);
            staticFunction();
        }
    }
    

    这里有几个问题需要弄清楚:

    1. Static Import无权改变无法使用本来就不能使用的静态成员的约束,上面例子的StaticTest和staticFieldsClass不是在同一个包下,所以StaticTest只能访问到staticFieldsClass中public的变量。使用了Static Import也同样如此。

    2. 导入的静态成员和本地的静态成员名字相同起了冲突,这种情况下的处理规则,是“本地优先。

    3. 不同的类(接口)可以包括名称相同的静态成员。例如在进行Static Import的时候,出现了“两个导入语句导入同名的静态成员”的情况。在这种时候,J2SE 1.5会这样来加以处理:

      1. 如果两个语句都是精确导入的形式,或者都是按需导入的形式,那么会造成编译错误。
      2. 如果一个语句采用精确导入的形式,一个采用按需导入的形式,那么采用精确导入的形式的一个有效。

    大家都这么聪明上面的几个特性我就不写例子了。

    static import这么叼那它有什么负面影响吗?

    答案是肯定的,去掉静态成员前面的类型名,固然有助于在频繁调用时显得简洁,但是同时也失去了关于“这个东西在哪里定义”的提示信息,理解或维护代码就呵呵了。
    但是如果导入的来源很著名(比如java.lang.Math),这个问题就不那么严重了。


    按需导入机制

    使用按需导入声明是否会降低Java代码的执行效率?

    绝对不会!

    一、import的按需导入

    import java.util.*;
    
    public class NeedImportTest {
        public static void main(String[] args) {
            ArrayList tList = new ArrayList();
        }
    }

    编译之后的class文件 :

    //import java.util.*被替换成import java.util.ArrayList
    //即按需导入编译过程会替换成单类型导入。
    import java.util.ArrayList;
    
    public class NeedImportTest {
        public static void main(String[] args) {
            new ArrayList();
        }
    }
    

    二、static import的按需导入

    import static com.assignment.test.StaticFieldsClass.*;
    public class StaticNeedImportTest {
        public static void main(String[] args) {
            System.out.println(staticField);
            staticFunction();
        }
    }

    上面StaticNeedImportTest 类编译之后 :

    //可以看出 : 
    //1、static import的精准导入以及按需导入编译之后都会变成import的单类型导入
    import com.assignment.test.StaticFieldsClass;
    
    public class StaticNeedImportTest {
        public static void main(String[] args) {
        //2、编译之后“打回原形”,使用原来的方法调用静态成员
            System.out.println(StaticFieldsClass.staticField);
            StaticFieldsClass.staticFunction();
        }
    }

    附加

    这是否意味着你总是可以使用按需导入声明?
    是,也不是!

    在类似Demo的非正式开发中使用按需导入声明显得很有用。

    然而,有这四个理由让你可以放弃这种声明:

    1. 编译速度:在一个很大的项目中,它们会极大的影响编译速度.但在小型项目中使用在编译时间上可以忽略不计。
    2. 命名冲突:解决避免命名冲突问题的答案就是使用全名。而按需导入恰恰就是使用导入声明初衷的否定。
    3. 说明问题:毕竟高级语言的代码是给人看的,按需导入看不出使用到的具体类型。
    4. 无名包问题:如果在编译单元的顶部没有包声明,Java编译器首选会从无名包中搜索一个类型,然后才是按需类型声明。如果有命名冲突就会产生问题。

    Sun的工程师一般不使用按需类型导入声明.这你可以在他们的代码中找到:
    在java.util.Properties类中的导入声明:

    import java.io.IOException;
    import java.io.PrintStream;
    import java.io.PrintWriter;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.io.Reader;
    import java.io.Writer;
    import java.io.OutputStreamWriter;
    import java.io.BufferedWriter;
    import java.security.AccessController;
    import java.security.PrivilegedAction;

    可以看到他们用单类型导入详细的列出了需要的java.io包中的具体类型。

    展开全文
  • python中__import__与import的区别

    万次阅读 2018-11-10 14:24:00
    最近在阅读一些python代码,发现有的项目里面不直接使用“import”,而是通过“__import()__”函数来导入模块。 那么这两者究竟有什么不同呢?  import导入的是一个标准模块,而标准模块的概念是一个文件夹里面...

    最近在阅读一些python代码,发现有的项目里面不直接使用“import”,而是通过“__import()__”函数来导入模块。

    那么这两者究竟有什么不同呢? 

    1. import导入的是一个标准模块,而标准模块的概念是一个文件夹里面必须包含__init__.py文件。它的作用更像是一种声明,且import模块进来之后,万一原本的模块有什么变化,可以通过reload()进行重新加载。
    2. __import__()作为一个函数,只能接受字符串参数,返回值可以直接用来操作,通常在动态加载的时候用到这个函数,最常见的情景就是插件功能的支持。
    __import__与import的对比
      import __import__
    倾向 固定式声明 动态加载
    适用场景 已经明确知道项目中哪些模块 模块可以动态插拔、动态引入运行
    举例 import os  #导入固有的os模块 __import__('employee').find(name='李林')   #动态加载刚安装的员工管理模块,并且查找一个叫“李林”的人

     

    展开全文
  • Python 3.x | 史上最详解的 导入(import

    万次阅读 多人点赞 2020-09-22 09:19:53
    win10+Python 3.6.3 一、理解一些基本概念 1、包、模块 模块 module:一般情况下,是一个以.py为后缀的文件。其他可作为module的文件类型还有”.pyo”、”.pyc”、”.pyd”、”.so”、”.dll”,但Python初学者...

    如需转载请注明出处。
    win10+Python 3.6.3

    一旦使用多层文件架构就很容易遇上import的坑!哈哈。

    一、理解一些基本概念

    1、模块、包
    **模块 module:**一般情况下,是一个以.py为后缀的文件。其他可作为module的文件类型还有".pyo"、".pyc"、".pyd"、".so"、".dll",但Python初学者几乎用不到。
    module 可看作一个工具类,可共用或者隐藏代码细节,将相关代码放置在一个module以便让代码更好用、易懂,让coder重点放在高层逻辑上。
    module能定义函数、类、变量,也能包含可执行的代码。module来源有3种:
    ①Python内置的模块(标准库);
    ②第三方模块;
    ③自定义模块。

    包 package: 为避免模块名冲突,Python引入了按目录组织模块的方法,称之为 包(package)。包 是含有Python模块的文件夹。
    这里写图片描述
    当一个文件夹下有   init   .py时,意为该文件夹是一个包(package),其下的多个模块(module)构成一个整体,而这些模块(module)都可通过同一个包(package)导入其他代码中。

    其中   init   .py文件 用于组织包(package),方便管理各个模块之间的引用、控制着包的导入行为。
    该文件可以什么内容都不写,即为空文件(为空时,仅仅用import [该包]形式 是什么也做不了的),存在即可,相当于一个标记。
    但若想使用from pacakge_1 import *这种形式的写法,需在  init  .py中加上:   all    = [‘file_a’, ‘file_b’] #package_1下有file_a.py和file_b.py,在导入时   init   .py文件将被执行。
    但不建议在   init   .py中写模块,以保证该文件简单。不过可在   init   .py导入我们需要的模块,以便避免一个个导入、方便使用。

    其中,   all   是一个重要的变量,用来指定此包(package)被import *时,哪些模块(module)会被import进【当前作用域中】。不在   all   列表中的模块不会被其他程序引用。可以重写  all  ,如   all    = [‘当前所属包模块1名字’, ‘模块1名字’],如果写了这个,则会按列表中的模块名进行导入。

    在模糊导入时,形如from package import *,*是由__all__定义的。

    精确导入,形如 from package import *、import package.class。

       path   也是一个常用变量,是个列表,默认情况下只有一个元素,即当前包(package)的路径。修改   path   可改变包(package)内的搜索路径。

    当我们在导入一个包(package)时(会先加载   init   .py定义的引入模块,然后再运行其他代码),实际上是导入的它的   init   .py文件(导入时,该文件自动运行,助我们一下导入该包中的多个模块)。我们可以在   init   .py中再导入其他的包(package)或模块 或自定义类。

    2、sys.modules、命名空间、模块内置属性
    2.1 sys.modules
    官方解释:链接
    sys.modules 是一个 将模块名称(module_name)映射到已加载的模块(modules) 的字典。可用来强制重新加载modules。Python一启动,它将被加载在内存中。
    当我们导入新modules,sys.modules将自动记录下该module;当第二次再导入该module时,Python将直接到字典中查找,加快运行速度。

    它是个字典,故拥有字典的一切方法,如sys.modules.keys()、sys.modules.values()、sys.modules[‘os’]。但请不要轻易替换字典、或从字典中删除某元素,将可能导致Python运行失败。

    import sys
    print(sys.modules)#打印,查看该字典具体内容。
    

    2.2 命名空间
    如同一个dict,key 是变量名字,value 是变量的值。

    • 每个函数function 有自己的命名空间,称local namespace,记录函数的变量。
    • 每个模块module 有自己的命名空间,称global namespace,记录模块的变量,包括functions、classes、导入的modules、module级别的变量和常量
    • build-in命名空间,它包含build-in function和exceptions,可被任意模块访问。

    某段Python代码访问 变量x 时,Python会所有的命名空间中查找该变量,顺序是:

    1. local namespace 即当前函数或类方法。若找到,则停止搜索;
    2. global namespace 即当前模块。若找到,则停止搜索;
    3. build-in namespace Python会假设变量x是build-in的函数函数或变量。若变量x不是build-in的内置函数或变量,Python将报错NameError。
    4. 对于闭包,若在local namespace找不到该变量,则下一个查找目标是父函数的local namespace。

    例:namespace_test.py代码

    def func(a=1):
    	b = 2
    	print(locals())#打印当前函数(方法)的局部命名空间
    	'''
    	locs = locals()#只读,不可写。将报错!
    	locs['c'] = 3
    	print(c)
    	'''
    	return a+b
    func()
    glos = globals()
    glos['d'] = 4
    print(d)
    
    print(globals())#打印当前模块namespace_test.py的全局命名空间
    

    内置函数locals()、globals()返回一个字典。区别:前者只读、后者可写。

    命名空间 在from module_name import 、import module_name中的体现:from关键词是导入模块或包中的某个部分。

    1. from module_A import X:会将该模块的函数/变量导入到当前模块的命名空间中,无须用module_A.X访问了。
    2. import module_A:modules_A本身被导入,但保存它原有的命名空间,故得用module_A.X方式访问其函数或变量。

    2.3 模块内置属性

    1.    name   直接运行本模块,   name   值为   main   ;import module,   name   值为模块名字。
    2.    file   当前 module的绝对路径
    3.    dict   
    4.    doc   
    5.    package   
    6.    path   

    3、绝对导入、相对导入
    这里写图片描述
    3.1 绝对导入:所有的模块import都从“根节点”开始。根节点的位置由sys.path中的路径决定,项目的根目录一般自动在sys.path中。如果希望程序能处处执行,需手动修改sys.path。
    例1:c.py中导入B包/B1子包/b1.py模块

    import sys,os
    BASE_DIR = os.path.dirname(os.path.abspath(__file__))#存放c.py所在的绝对路径
    
    sys.path.append(BASE_DIR)
    
    from B.B1 import b1#导入B包中子包B1中的模块b1
    

    例2:b1.py中导入b2.py模块

    from B.B1 import b2#从B包中的子包B1中导入模块b2
    

    3.2 相对导入:只关心相对自己当前目录的模块位置就好。不能在包(package)的内部直接执行(会报错)。不管根节点在哪儿,包内的模块相对位置都是正确的。
    b1.py代码

    #from . import b2 #这种导入方式会报错。
    import b2#正确
    b2.print_b2()
    

    b2.py代码

    def print_b2():
    	print('b2')
    

    运行b1.py,打印:b2。

    在使用相对导入时,可能遇到ValueError: Attempted relative import beyond toplevel package
    解决方案:参考这篇文章,链接

    3.3 单独导入包(package):单独import某个包名称时,不会导入该包中所包含的所有子模块。
    c.py导入同级目录B包的子包B1包的b2模块,执行b2模块的print_b2()方法:
    c.py代码

    import B
    B.B1.b2.print_b2()
    

    运行c.py,会报错。

    解决办法
    B/   init   .py代码

    from . import B1#其中的.表示当前目录
    

    B/B1/   init   .py代码

    from . import b2
    

    此时,执行c.py,成功打印:b2。

    3.4 额外
    ①一个.py文件调用另一个.py文件中的类。
    如 a.py(class A)、b.py(class B),a.py调用b.py中类B用:from b import B
    ②一个.py文件中的类 继承另一个.py文件中的类。如 a.py(class A)、b.py(class B),a.py中类A继承b.py类B。

    from b import B
    class A(B):
    pass
    

    二、Python运行机制:理解Python在执行import语句(导入内置(Python自个的)或第三方模块(已在sys.path中))时,进行了啥操作?

    step1:创建一个新的、空的module对象(它可能包含多个module);
    step2:将该module对象 插入sys.modules中;
    step3:装载module的代码(如果需要,需先编译);
    step4:执行新的module中对应的代码。

    在执行step3时,首先需找到module程序所在的位置,如导入的module名字为mod_1,则解释器得找到mod_1.py文件,搜索顺序是:
    当前路径(或当前目录指定sys.path)----->PYTHONPATH----->Python安装设置相关的默认路径。

    对于不在sys.path中,一定要避免用import导入 自定义包(package)的子模块(module),而要用from…import… 的绝对导入 或相对导入,且包(package)的相对导入只能用from形式。

    1、“标准”import,顶部导入
    这里写图片描述
    有上述基础知识,再理解这个思维导图,就很容易了。在运用模块的变量或函数时,就能得心应手了。

    2、嵌套import

    2.1 顺序导入-import
    这里写图片描述

    PS:各个模块的Local命名空间的独立的。即:
    test模块 import moduleA后,只能访问moduleA模块,不能访问moduleB模块。虽然moduleB已加载到内存中,如需访问,还得明确地在test模块 import moduleB。实际上打印locals(),字典中只有moduleA,没有moduleB。

    2.2 循环导入/嵌套导入-import
    这里写图片描述
    形如from moduleB import ClassB语句,根据Python内部import机制,执行细分步骤:

    1. 在sys.modules中查找 符号“moduleB”;
    2. 如果符号“moduleB”存在,则获得符号“moduleB”对应的module对象;
      从的   dict__中获得 符号“ClassB”对应的对象。如果“ClassB”不存在,则抛出异常“ImportError: cannot import name ‘classB’”
    3. 如果符号“moduleB”不存在,则创建一个新的 module对象。不过此时该新module对象的   dict   为空。然后执行moduleB.py文件中的语句,填充的   dict   

    总结:from moduleB import ClassB有两个过程,先from module,后import ClassB。
    这里写图片描述

    当然将moduleA.py语句 from moduleB import ClassB改为:import moduleB,将在第二次执行moduleB.py语句from moduleA import ClassA时报错:ImportError: cannot import name ‘classA’

    解决这种circular import循环导入的方法:
    例比:安装无线网卡时,需上网下载网卡驱动;
    安装压缩软件时,从网上下载的压缩软件安装程序是被压缩的文件。
    方法1----->延迟导入(lazy import):把import语句写在方法/函数里,将它的作用域限制在局部。(此法可能导致性能问题)
    方法2----->将from x import y改成import x.y形式
    方法3----->组织代码(重构代码):更改代码布局,可合并或分离竞争资源。
    合并----->都写到一个.py文件里;
    分离–>把需要import的资源提取到一个第三方.py文件中。
    总之,将循环变成单向。

    3、包(package)import
    在一个文件下同时有   init   .py文件、和其他模块文件时,该文件夹即看作一个包(package)。包的导入 和模块导入基本一致,只是导入包时,会执行这个   init   .py,而不是模块中的语句。
    而且,如果**只是单纯地导入包【形如:import xxx】**,而包的   init   .py中有没有明确地的其他初始化操作,则:此包下的模块 是不会被自动导入的。当然该包是会成功导入的,并将包名称放入当前.py的Local命名空间中。
    这里写图片描述
    [D:youcaihua\test\PkgDemo\mod.py]文件
    [D:youcaihua\test\PkgDemo\pkg1\pkg1_mod.py]文件
    [D:youcaihua\test\PkgDemo\pkg2\pkg2_mod.py]文件,三个文件同样的代码:

    def getName():
    	print(__name__)
    
    if __name__ == '__main__':
    	getName()
    

    [D:youcaihua\test\test.py]文件

    import PkgDemo.mod#1
    print(locals(),'\n')
    import PkgDemo.pkg1#2
    print(locals(),'\n')
    import PkgDemo.pkg1.pkg1_mod as m1#3
    print(locals(),'\n')
    import PkgDemo.pkg2.pkg2_mod#4
    PkgDemo.mod.getName()#5
    print('调用mod.py----', locals(), '\n')
    m1.getName()#6
    PkgDemo.pkg2.pkg2_mod.getName()#7
    

    执行 #1 后,将PkgDemo、PkgDemo.mod加入sys.modules中,此时可调用PkgDemo.mod的任何类、或函数。当不能调用包PkgDemo.pkg1或pkg2下任何模块。但当前test.py文件Local命名空间中只有 PkgDemo

    执行 #2 后,只是将PkgDemo.pkg1载入内存,sys.modules会有PkgDemo、PkgDemo.mod、PkgDemo.pkg1 三个模块。但PkgDemo.pkg1下的任何模块 都没有自动载入内存,所以在此时:PkgDemo.pkg1.pkg1_mod.getName()将会出错。当前test.py的Local命名空间依然只有PkgDemo。

    执行 #3 后,会将pkg1_mod载入内存,sys.modules会有PkgDemo、PkgDemo.mod、PkgDemo.pkg1、PkgDemo.pkg1.pkg1_mod四个模块,此时可执行PkgDemo.pkg1.pkg1_mod.getName()。由于使用了as,当前Local命名空间将另外添加m1(作为PkgDemo.pkg1.pkg1_mod的别名)、当然还有PkgDemo。

    执行 #4 后,会将PkgDemo.pkg2、PkgDemo.pkg2.pkg2_mod载入内存,sys.modules中会有PkgDemo、PkgDemo.mod、PkgDemo.pkg1、PkgDemo.pkg1.pkg1_mod、PkgDemo.pkg2、PkgDemo.pkg2.pkg2_mod六个模块,当然:当前Local命名空间还是只有PkgDemo、m1。

    #5#6#7当然都可正确执行。

    三、How to avoid Python circle import error?如何避免Python的循环导入问题?

    代码布局、(架构)设计问题,解决之道是:将循环变成单向。采用分层、用时导入、相对导入(层次建议不要超过两个)

    注意:在命令行执行Python xx.py、与IDE中执行,结果可能不同。

    如需转载请注明出处。
    参考:
    官方规范

    展开全文
  • __import__详解

    万次阅读 2019-06-14 11:06:32
    当使用import导入Python模块的时候,默认调用的是__import__()函数。直接使用该函数的情况很少见,一般用于动态加载模块。 __import__(name, globals, locals, fromlist, level)只有name是必选参数,其他都是可选...
  • import和__import__()有什么不同?

    千次阅读 2018-10-28 10:22:29
    import作用: 导入/引入一个python标准模块,其中包括.py文件、带有__init__.py文件的目录; __import__作用: 同import语句同样的功能,但__import__是一个函数,并且只接收字符串作为参数,所以它的作用就可想而知...
  • @Import注解的作用

    千次阅读 2020-06-04 11:03:04
    这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、...
  • 有关Python的import...和from...import...的区别

    万次阅读 多人点赞 2020-01-09 16:50:18
    1、语法分析:首先from A import a1 是从A模块导入a1工具(可以是某个 函数,全局变量,类),import A是导入整个A模块的全部内容(包括全部的函数,全局变量,类)。 2、内存分析:from...import...会在内存中创建...
  • import ... from和import {} from 的区别

    万次阅读 2018-08-01 11:30:55
    1. import { isvalidUsername ,validateUrl} from '@/utils/validate' //也可以分开两次写,导入的时候都带花括号   2. import isvalidUsername from '@/utils/validate' //导入的时候没有花括号   ...
  • Spring中@Import注解的作用和使用

    万次阅读 2018-09-28 14:05:11
    @Import用来导入@Configuration注解的配置类、声明@Bean注解的bean方法、导入ImportSelector的实现类或导入ImportBeanDefinitionRegistrar的实现类。 @Import注解的作用 查看Import注解源码 /** * Indicates one ...
  • es6 import()函数

    万次阅读 多人点赞 2018-02-05 20:15:25
    import()函数 简介 前面介绍过,import命令会被 JavaScript 引擎静态分析,先于模块内的其他模块执行(叫做”连接“更合适)。所以,下面的代码会报错。 // 报错if (x === 2) { import MyModual from './...
  • unused import statement解决方法

    万次阅读 多人点赞 2016-10-12 18:57:06
    file下有invalidate caches/restart选项,点击即可
  • Python中from...importimport......as的区别

    万次阅读 多人点赞 2016-08-26 13:53:44
    from...import 如 from A import b,相当于 import A b=A.b 再如: "from t2 import var1" 相当于: import t2 var1= t2.var1 在此过程中有一个隐含的赋值的过程 import......as import A as B,给予A库一...
  • 以上只是提醒你导入了但没有使用,不是报错,原因好像是因为开了PEP8自动检查 TKS!
  • Unused import statement解决方法

    万次阅读 热门讨论 2018-08-20 08:08:54
    前言:  一直都能运行的项目,不知道怎么回事就突然报了这个问题   问题截图:   问题原因:  maven导入的项目的pom文件出了问题   问题解决:  在IDEA中找到pom文件右击-...虽然是自己粗心而为...
  • IDEA 修改Import 不是improt* 为单独import

    万次阅读 2014-10-17 09:51:38
    IDEA 修改Import 不是improt* 为单独import
  • from __future__ import absolute_import的作用

    万次阅读 多人点赞 2016-04-03 16:20:56
    关于这句from __future__ import absolute_import的作用: 直观地看就是说”加入绝对引入这个新特性”。说到绝对引入,当然就会想到相对引入。那么什么是相对引入呢?比如说,你的包结构是这样的: pkg/ pkg/init.py...
  • Python中import, from...import,import...as的区别

    万次阅读 多人点赞 2017-07-26 10:04:47
    在python中import或者from…import是用来导入相应的模块。举个例子:import datetime print(datetime.datetime.now())以上代码实现输出系统当前时间,是引入整个datetime包,然后再调用datetime这个类中的now()方法...
  • golang中("import cycle not allowed")错误

    万次阅读 2016-12-30 15:44:08
    golang不允许循环导包,如果检测到import cycle,会在编译时报错,通常import cycle是因为设计错误或包的规划问题。 import( "package A" "package B" ) 如果package A中已经导入package B,而本package中...
  • import numpy 和 from numpy import*的区别

    万次阅读 2017-10-22 21:06:51
    import numpy,如果使用numpy的属性都需要在前面加上numpy from numpy import *,则不需要加入numpy 后者不建议使用,如果下次引用和numpy里的函数一样的情况,就会出现命名冲突。
1 2 3 4 5 ... 20
收藏数 3,845,070
精华内容 1,538,028
关键字:

import