Python import语法

本质上import有关联的概念是python的文件架构,python的文件层级架构是包-模块-类-函数,不像C语言,python语言是没有块的概念的,这也意味着诸如if、while、for等语句是无法定义局部变量的,这些语句内部定义的变量与外部定义完全相同。import语句针对的是模块之间的include,同时支持跨包的import。

1、import / from…import / import … as

以近期从事的代码改造为例,以上三种情况可以写作:

  • import utils
    需要说明的是import utils这种写法偶尔会写作:from utils import * ,区别在于同样的在新文件中调用model_path时,第一种写法需要写作:utils.model_path,第二种写法则可以直接写作model_path的形式进行调用;这个是吃了一个小亏的在这儿;但是为了防止命名空间的污染,建议还是使用import utils这种写法。
  • from lib.utils import model_path
    这种写法多是因为跨包输入的原因,将部分方法类型的文件、参数类型的文件防止在单独的包内进行管理,便于代码管理;
  • import model_path as path
    import model_path as path最好理解,就是对于原变量名的改写,最常见的句式是import numpy as np。
2、import 导入重复语句

在C++中,include语句需要在头部定义 #ifndef #define 的语句来防止相同头文件的多次导入,控制代码的臃肿。而在python中,系统会自动通过头文件的搜索过程来阻止重复包含头文件现象的发生。

一个模块的导入过程主要分三步:搜索、加载 和 名字绑定。

1)搜索
搜索是整个导入过程的核心,也是最为复杂的一步。对于被导入模块M,按照先后顺序,搜索的处理步骤为:
在缓存 sys.modules 中查找模块M,若找到则直接返回模块M
否则,顺序搜索 sys.meta_path,逐个借助其中的 finder 来查找模块M,若找到则加载后返回模块M
否则,如果模块M在一个包P中(如import P.M),则以P.__path__为搜索路径进行查找;如果模块M不在一个包中(如import M),则以 sys.path 为搜索路径进行查找。
此时可以明确的是:Python导入系统使用缓存(在sys.modules字典中)来防止模块被导入两次。import在代码中的任何地方调用相同的名称将从第一次产生相同的模块对象,从而使模块对象成为“单例”。

2)加载
正如 『搜索』 步骤中所述,对于找到的模块M:如果M在缓存 sys.modules 中,则直接返回;否则,会加载M。加载 是对模块的初始化处理,包括以下步骤:
设置属性:包括__name__、filepackage__和__loader(对于包,则还有__path__)
编译源码:将模块文件(对于包,则是其对应的__init__.py文件)编译为字节码(*.pyc),如果字节码文件已存在且仍然是最新的,则不会重编
执行字节码:执行编译生成的字节码(即模块文件或__init__.py文件中的语句)
有一点值得注意的是,加载不只是发生在导入时,还可以发生在 reload() 时。

3)名字绑定
加载完importee模块后,作为最后一步,import语句会为 导入的对象 绑定名字,并把这些名字加入到importer模块的名字空间中。其中,导入的对象 根据导入语句的不同有所差异:
如果导入语句为import obj,则对象obj可以是包或者模块
如果导入语句为from package import obj,则对象obj可以是package的子包、package的属性或者package的子模块
如果导入语句为from module import obj,则对象obj只能是module的属性

3、import 绝对导入与相对导入

相对导入:
当项目规模变大,代码复杂度上升的时候,我们通常会把一个一个的 .py 文件组织成一个包,让项目结构更加清晰。这时候 import 又会出现一些问题,比如:一个典型包的目录结构是这样的:
string/
├── __init__.py
├── find.py
└── foo.py
如果 string/foo.py 的代码如下:
# string/foo.py

from string import find
print(find)

那么 python string/foo.py 的运行结果会提示你找不到对应的模块<module ‘string.find’ from ‘string/find.py’>
此时需要借助于python命令语句选项:python xxx.py 就是直接运行,python -m xxx 则相当于import,把该文件当做模块来启动,两者的主要区别在于sys.path不同,直接运行会将该脚本所在目录添加至sys.path,当做模块启动则会将当前运行命令的路径添加至sys.path。

其实目的是为了解决同一个包内彼此难以import的问题,而相对 import 就是专为解决「包内导入」(intra-package import)而出现的。它的使用也很简单,from 的后面跟个 . 就行:

from . import ...

.的个数代表不同文件夹层级,一个.代表当前文件夹,两个则代表上一个文件夹。上面的例子可以写作:

from . import find

绝对导入:
绝对 import 和相对 import 很好区分,从行为上来看,绝对 import 会通过搜索 sys.path 来查找模块;从使用场景上面看,绝对import占据了绝大多的import场景,

所有的 import … 都是绝对 import
所有的 from XXX import … 都是绝对 import

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值