前言

经常用到import,module,对其中的机制及原理有一定的了解,但没有将各种信息前后连通起来,经整理python 的引用及包相关资料形成此文档。

 

参考文档:

  1. https://docs.python.org/3/reference/import.html


 

1.      关于import

python常用的引用方法:

1. import <module>
2. built-in function: __import__()
3. importlib: importlib.import_module()

 

import statement 进行两个操作:搜索指定模板,把结果绑定到local scope的一个命名上。

import声明的搜索实际是调用__import__(),当然得有参数;__import__()返回的结果进行绑定

。<参考:https://docs.python.org/3/reference/simple_stmts.html#import>

当一个模板文件被引用,python找到它,创建一个module object,then initializing it。

如果没有找到,触发异常ModuleNotFoundError。

注意一个模块只会导入一次,再次导入会返回已生成的对象,是单例模式。

 

1.1.    importlib

The importlib module provides a rich API for interacting with the import system. For example importlib.import_module() provides a recommended, simpler API than built-in __import__() for invoking the import machinery. Refer to the importlib library documentation for additional detail.

一般用不到,了解即可。

 

1.2.    导入非本目录模块及搜索顺序

对模块位置的搜索顺序是:

脚本当前目录

shell 变量 PYTHONPATH 下的每个目录。

Python默认路径(依赖于安装环境)。UNIX下,默认路径一般为/usr/local/lib/python/。

 

目录下级模块:

import <path>.<module>

也可在下级目录中建立__init__.py文件,然后导入

目录上级模块:

要导入上级目录,把上级目录加到sys.path里:sys.path.append('../')

from fatherdirname import xxx

 

注意:

包下面最好不要有同名文件,如果父包和子包中都有一个tt.py文件,在子包的__init__.py中声明import tt当然没有问题,但在父包中import 子包时,会导入父包的tt.py而非子包的。

 

1.3.    删除模块

del #只在内存中删除,文件并未删除

 

1.4.    导入书写规范

import语句一般写在文件的头部;

 

不要一行导入多个模块,不提倡下面的写法:

import module1,module2,module3

 

在用import语句导入模块时最好按照这样的顺序:

1、python 标准库模块

2、python 第三方模块

3、自定义模块

 

2.      关于module

每个模块都有自己的私有符号表,模块中所有的函数以它为全局符号表。因此,模块的作者可以在模块中使用全局变量,而不用担心与用户的全局变量发生意外冲突。另一方面,如果有需要,可以引用某一模块的全局变量,引用方法为modname.itemname。

 

2.1.    模块引用

import module

from module import function1, function2, function3

from [somemodule] import *

使用方法2引用时不会引用被引用模块的名称

方法3相当于方法2的变体,会导入所有的名称(names,自已理解,相当于属性+方法+变量….),除了以_开头的部分;不建议使用此方法,可能会覆盖同名对象(变量,函数等);

import module as <name>

 

2.2.    模块执行

模块也可以执行

python fibo.py <arguments>

注意:

if __name__ == “__main__”:

       pass

不解释

 

2.3.    模块特殊变量

模块是一个对象,它有一些属性在编程时会经常用到:

1. __doc__ 将文档的注释封装到该方法  """这种注释才会被封装"""

2. __file__ 获取模块文件的所在路径

3. __name__

       if __name__ == ‘__main__’:

打开一个.py文件时,经常会在代码的最下面看到if __name__ == '__main__':

模块是对象,并且所有的模块都有一个内置属性 __name__。一个模块的 __name__ 的值取决于如何应用模块。如果 import 一个模块,那么模块__name__ 的值通常为模块文件名,不带路径或者文件扩展名。但是您也可以像一个标准的程序样直接运行模块,在这 种情况下, __name__ 的值将是一个特别缺省"__main__"。

 

4. __cached__
5. __package__指定的函数从哪个模块导入
from bin import admin
print(__package__)
print(admin.__package__)
 
# 结果:
None
bin

 

3.      关于package

Python只有一种module object,无论它是python, c 或者其它语言,都是这一种对象。

package提供了更高层级的组织结构和命名层级,基本上可以想象成一个类似文件系统的结构。

记住包一定是模块,但反之不然。Specifically, any module that contains a __path__ attribute is considered a package.

 

3.1.    regular packages and namespace packages

python 定义了两种类型的包,regular packages and namespace packages。

常规包近似于存在__init__.py的目录。导入常规包时,python将隐式执行__init__.py。

 

namespace:

命名空间包可以理解为存放于不同路径下的部件的组合,部件可以在任何地方(例如zip文件,网络),也可能是虚拟模块。

当然,命名空间包不能使用普通列表作为__path__属性,它使用自定义迭代类型,可以自动去搜索包的组件。

估计一般的项目也不会使用这么复杂的代码存放/组织结构,了解即可。

 

3.2.    引用

可以使用import 导入包,或使用from +import导入包中的部分模块;

包目录第一个文件应该是__init__.py,如果子目录中也有__init__.py,那么它就是这个包的子包了。

引用包

1). import PackageA.SubPackageA.ModuleA,使用时必须用全路径名

2). 变种: from PackageA.SubPackageA import ModuleA, 可以直接使用模块名而不用加上包前缀。

3). 也可以直接导入模块中的函数或变量:from PackageA.SubPackageA.ModuleA import functionA

 

import语句语法:

1. 当使用from package import item时,item可以是package的子模块或子包,或是其他的定义在包中的名字(比如一个函数、类或变量)

   首先检查item是否定义在包中,不过没找到,就认为item是一个模块并尝试加载它,失败时会抛出一个ImportError异常。

2. 当使用import item.subitem.subsubitem语法时,最后一个item之前的item必须是包,最后一个item可以是一个模块或包,但不能是类、函数和变量

 

3. from pacakge import *

   如果包的__init__.py定义了一个名为__all__的列表变量,它包含的模块名字的列表将作为被导入的模块列表。

   如果没有定义__all__, 这条语句不会导入所有的package的子模块,它只保证包package被导入,然后导入定义在包中的所有名字。

 

3.3.    包的特殊属性

1.__name__

2.__loader__:The loader to use for loading. For namespace packages this should be set to None.

3.__file__:Name of the place from which the module is loaded, e.g. “builtin” for built-in modules and the filename for modules loaded from source. Normally “origin” should be set, but it may be None (the default) which indicates it is unspecified (e.g. for namespace packages).

4.__path__:List of strings for where to find submodules, if a package (None otherwise).

5.__cached__:String for where the compiled module should be stored (or None).

6.__package__:(Read-only) Fully-qualified name of the package to which the module belongs as a submodule (or None).

7.has_location:Boolean indicating whether or not the module’s “origin” attribute refers to a loadable location.

 

3.4.    文件__init__.py

通常__init__.py 文件为空,但也可以为它增加其他的功能。

在导入一个包时,实际上是导入了它的__init__.py文件。

>>> m # module

<module 'm' from '……code test\\m.py'>

>>> import mypackage #package

>>> mypackage

<module 'mypackage' from '…….\\mypackage\\__init__.py'>

>>> import scrapy #package

>>> scrapy

<module 'scrapy' from '……\lib\\site-packages\\scrapy\\__init__.py'>

 

这样可以在__init__.py文件中批量导入我们所需要的模块,而不再需要一个一个的导入;__init__.py中还有一个重要的变量,__all__, 也是用来控制导入对象的。

下例中2行和3 行是等效的。

# __init__.py

#import t_sub

__all__ = ['t_sub']

#__all__ = [‘t_sub’, ‘t_sub2’]

 

上面有两个不同的__all__变量:

如果使用import mypackage.t_sub2 或from mypackage.t_sub2 import p

是没有什么区别的,但使用import <> 或from <> import *就不同了;它们会按照all给出的对象导入。

第一种__all__导入方式不会导入t_sub2。

 

4.      其它

4.1.    关于.pyc 文件 与 .pyo 文件

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