python import 的导入机制

详细了解一下import语句引用机制:

可以被import语句导入的对象是以下类型:

模块文件(.py文件)
C或C++扩展(已编译为共享库或DLL文件)
包(包含多个模块)
内建模块(使用C编写并已链接到Python解释器中)

模块通常为单独的.py文件,可以用import直接引用,可以作为模块的文件类型有.py、.pyo、.pyc、.pyd、.so、.dll

当导入模块时,解释器按照sys.path列表中的目录顺序来查找导入文件。

import sys
>>> print(sys.path)

# Linux:
['', '/usr/local/lib/python3.4',
 '/usr/local/lib/python3.4/plat-sunos5',
 '/usr/local/lib/python3.4/lib-tk',
 '/usr/local/lib/python3.4/lib-dynload',
 '/usr/local/lib/python3.4/site-packages']

# Windows:
['', 'C:\\WINDOWS\\system32\\python34.zip', 'C:\\Documents and Settings\\weizhong', 
'C:\\Python34\\DLLs', 'C:\\Python34\\lib', 'C:\\Python34\\lib\\plat-win', 
'C:\\Python34\\lib\\lib-tk', 'C:\\Python34\\Lib\\site-packages\\pythonwin', 'C:\\Python34', 
'C:\\Python34\\lib\\site-packages', 'C:\\Python34\\lib\\site-packages\\win32', 
'C:\\Python34\\lib\\site-packages\\win32\\lib', 'C:\\Python34\\lib\\site-packages\\wx-2.6-msw-unicode']

其中list第一个元素空字符串代表当前目录。

python import引入不同路径下的模块

几种常用情况:
(1)主程序与模块程序在同一目录下:
如下面程序结构:
`-- src

|-- mod1.py 
`-- test1.py 
若在程序test1.py中导入模块mod1, 则直接使用 import  mod1或from mod1 import *; 

(2)主程序所在目录是模块所在目录的父(或祖辈)目录
如下面程序结构:
`-- src

|-- mod1.py 
|-- mod2 
|   `-- mod2.py 
`-- test1.py 
若在程序test1.py中导入模块mod2, 需要在mod2文件夹中建立空文件__init__.py文件(也可以在该文件中自定义输出模块接口); 然后使用 from mod2.mod2 import * 或import mod2.mod2.  //相对路径.导入文件名

3)主程序导入上层目录中模块或其他目录(平级)下的模块
如下面程序结构:
`-- src

|-- mod1.py 
|-- mod2 
|   `-- mod2.py 
|-- sub 
|   `-- test2.py 
`-- test1.py 
若在程序test2.py中导入模块mod1和mod2。首先需要在mod2下建立__init__.py文件(同(2)),src下不必建立该文件。然后调用方式如下: 

下面程序执行方式均在程序文件所在目录下执行,如test2.py是在cd sub;之后执行python test2.py
而test1.py是在cd src;之后执行python test1.py; 不保证在src目录下执行python sub/test2.py成功
import sys
sys.path.append("..") #在系统检索路径中增加包的检索根路径
import mod1
import mod2.mod2 #把..路径加到检索路径中

4) 导入包
多个相关联的模块组成一个包,以便于维护和使用,同时能有限的避免命名空间的冲突。一般来说,包的结构可以是这样的:

package
|- subpackage1

  |- __init__.py
  |- a.py

|- subpackage2

  |- __init__.py
  |- b.py

有以下几种导入方式:

import subpackage1.a # 将模块subpackage.a导入全局命名空间,例如访问a中属性时用subpackage1.a.attr
from subpackage1 import a # 将模块a导入全局命名空间,例如访问a中属性时用a.attr_a
from subpackage.a import attr_a # 将模块a的属性直接导入到命名空间中,例如访问a中属性时直接用attr_a
使用from语句可以把模块直接导入当前命名空间,from语句并不引用导入对象的命名空间,而是将被导入对象直接引入当前命名空间。引用时直接引用import后面的即可:a.fun(),不用再subpackage1.a.fun()了。

总结:
  通过总结可以发现,当你要导入的文件在和你的当前文件在同一个目录时,你直接导入这个文件名就好了。

  当你要导入的文件或者目录不和你的当前文件同目录时,你需要跳到这个你要导入文件的父级目录,然后一级一级的用点号连接走过的目录或者文件,然后就可以了 至于要怎么跳到这个这个父级目录。比较通用的就是,将父级目录加入系统路径,然后用点号一级一级的寻找,直到到达你要导入的模块。

包的定议文件__init__.py

__init__.py 文件定义了包的属性和方法。其实它可以什么也不定义;可以只是一个空文件,但是必须存在。如果 __init__.py 不存在,这个目录就仅仅是一个目录,而不是一个包,它就不能被导入或者包含其它的模块和嵌套包

__init__.py的作用有如下几点:

  1. 相当于class中的def __init__(self):函数,用来初始化模块。
  2. 把所在目录当作一个package处理
  3. from-import 语句导入子包时需要用到它。 如果没有用到, 他们可以是空文件。
    如引入package.module下的所有模块

from package.module import *
这样的语句会导入哪些文件取决于操作系统的文件系统. 所以我们在__init__.py 中加入 __all__变量.
该变量包含执行这样的语句时应该导入的模块的名字. 它由一个模块名字符串列表组成.

当导入包时,python会自动执行 "__init__.py" 里的代码,可作包和模块的初始化
__all__=[cl,c2] #定议包中哪些模块可以被导入

[详细了解>>]

模块的内置变量

  1. dir()函数:返回模块的所有变量名称
  2. __**__:表示内置变量
    eg:__name__ 表示命名空间;__package__ 表示包名称;__doc__ 表示模块注释;__file__ 表示模块路径

print("name:"+__name__)

入口文件和普通模块内置变量的区别

如果一个 .py 文件被当做一个应用程序的入口:1. 它的名称不再是本身模块的名称,而是被强制更改为 "__main__"2. 它不属于任何包3. file内置变量不会像普通模块一样显示绝对路径,它所显示的值也是不确定值,和执行命令所在的目录有关(详情见第二张图)※ Python的入口文件和普通导入的模块文件是有差异的

让python脚本成为一个普通模块被其他应用程序调用,也可以让自己成为一个可执行文件
有时候一个模块既想被作为一个可执行文件,又想成为一个普通的模块。当它们处于两种不同的情形下时,有些逻辑处理时不相同的,所以如果想知道此时模块时处于什么情形,可以使用如下代码if  __name__ == '__main__':    pass,来判断当前模块是否是一个入口文件

if __name__ == "__main__":
    print("this is a App")  #入口文件作为可执行文件时,可以把相关执行代码写在这里
print("this is a module")   #普通的模版调用

Python中的普通模块必须有一个包,当想要把一个可执行文件当做一个普通模块运行时,可以使用 -m 参数

python -m 命名空间.模块名(package_name.module_name) 
  1. import 不支持相对导入,只能使用 from ... import ... 格式实现相对导入
  2. 入口文件中不能使用相对导入,因为它没有包的概念
  3. 使用相对导入不要超出顶级包,入口文件同级的都不能使用相对导入
  4. 实在想用相对路径导入,此时把入口文件当做一个模块来执行,用 python -m demo.main

关于.pyc 文件 与 .pyo 文件

.py文件的汇编,只有在import语句执行时进行,当.py文件第一次被导入时,它会被汇编为字节代码,并将字节码写入同名的.pyc文件中。后来每次导入操作都会直接执行.pyc 文件(当.py文件的修改时间发生改变,这样会生成新的.pyc文件),在解释器使用-O选项时,将使用同名的.pyo文件,这个文件去掉了断言(assert)、断行号以及其他调试信息,体积更小,运行更快。(使用-OO选项,生成的.pyo文件会忽略文档信息)
python -o filename.py #create .pyo
python -oo flename.py #create .pyo file size smaller

用pip安装的python扩展模块的位置

Windows: python目录下Libsite-packages;
Linux: /usr/local/lib/python/dist-packages/。

包导入的一些技巧

1。确定需要用包中的哪个函数,可以用from package.module import * 的格式,可以直接把函数导入当前的命名空间
2。当模块的名称过长或不便书写时,可用 import 模块名 as alias 名称来定义包的别名。引用时可直接用alias.fun()替代

eg:import  t.c7  as  m
print (m.a)

将第三方库的包导入到项目文件中的设置

1.将第三方库都复制到项目文件夹中,如lib文件夹中。建立__init__.py文件。将文件夹定义为包
2.复制相应的模块库,可以复制的地点有python/lib/site-packages,虚拟环境的site-packages,以及用户/appdata/lib/site-packages中。
3.在项目入口文件中执行路径导入语句:
import sys
import os
a = file # __file__全局变量获取当前文件路径
print(a)
b = os.path.dirname(a) #获取文件当前目录
print(b)
c = "lib" #自定义文件目录名称
d = os.path.join(b,c) #将获取文件当前目录,与自定义文件目录名称,拼接成完整的路径
print(d)
print("n")
sys.path.append(d) #将拼接好的路径,添加到解释器模块路径中
4。测试加修改