模块的搜索路径
模块的搜索路径都放在了sys.path列表中,如果缺省的sys.path中没有含有自己的模块或包的路径,可以动态的加入
(sys.path.apend)即可。下面是sys.path在Windows平台下的添加规则。
1、sys.path第一个路径往往是主模块所在的目录。在交互环境下添加一个空项,它对应当前目录。
2、如果PYTHONPATH环境变量存在,sys.path会加载此变量指定的目录。
3、我们尝试找到Python Home,如果设置了PYTHONHOME环境变量,我们认为这就是Python
Home,否则,我们使用python.exe所在目录找到lib\os.py去推断Python Home。
如果我们确实找到了Python Home,则相关的子目录(Lib、plat-win、lib-tk等)将以Python
Home为基础加入到sys.path,并导入(执行)lib/site.py,将site-specific目录及其下的包加入。
如果我们没有找到Python
Home,则把注册表Software\Python\PythonCore\2.5\PythonPath的项加入sys.path(HKLM和
HKCU合并后加入),但相关的子目录不会自动添加的。
4、如果我们没有找到Python
Home,并且没有PYTHONPATH环境变量,并且不能在注册表中找到PythonPath,那么缺省相对路径将加入(如:.\Lib;.
\plat-win等)。
总结如下:
当在安装好的主目录中运行Python.exe时,首先推断Python
Home,如果找到了PythonHome,注册表中的PythonPath将被忽略;否则将注册表的PythonPath加入。
如果PYTHONPATH环境变量存在,sys.path肯定会加载此变量指定的目录。
如果Python.exe在另外的一个目录下(不同的目录,比如通过COM嵌入到其他程序),Python
Home将不推断,此时注册表的PythonPath将被使用。
如果Python.exe不能发现他的主目录(PythonHome),并且注册表也没有PythonPath,则将加入缺省的相对目录。
标准Import
Python中所有加载到内存的模块都放在sys.modules。当import一个模块时首先会在这个列表中查找是否已经加载了此模块,如果加
载了则只是将模块的名字加入到正在调用import的模块的Local名字空间中。如果没有加载则从sys.path目录中按照模块名称查找模块文件,模
块文件可以是py、pyc、pyd,找到后将模块载入内存,并加入到sys.modules中,并将名称导入到当前的Local名字空间。
可以看出了,一个模块不会重复载入
。多个不同的模块都可以用import引入同一个模块到自己的Local名字
空间,其实背后的PyModuleObject对象只有一个。
说一个容易忽略的问题,import只能导入模块,不能导入模块中的对象(类、函数、变量等)。
如一个模块
A(A.py)中有个函数getName,另一个模块不能通过import A.getName将getName导入到本模块,只能用import
A。如果想只导入特定的类、函数、变量则用from A import getName即可。
嵌套Import
嵌套import,我分两种情况,一种是:本模块导入A模块(import
A),而A中又有import语句,会激活另一个import动作,如import B,而B模块又可以import其他模块,一直下去。
对这种嵌套比较容易理解,注意一点就是各个模块的Local名字空间是独立的,所以上面的例子,本模块import
A完了后本模块只能访问模块A,不能访问B及其他模块。虽然模块B已经加载到内存了,如果要访问还要在明确的在本模块中import B。
另外一种嵌套指,在模块A中import B,而在模块B中import
A。这时会怎么样呢?这个在Python列表中由RobertChen给出了详细解释,抄录如下:
[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内部会分成几个步骤:
- 在sys.modules中查找符号"B"
- 果符号B存在,则获得符号B对应的module对象<module B>。
从<module B>的__dict__中获得符号"D"对应的对象,如果"D"不存在,则抛出异常
-
如果符号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中已经存在,所以是不会抛出异常的。
上面的解释已经由Zoom.Quiet收录在啄木鸟
了,里面有图,可以参考一下。
Package(包) Import
包(Package)可以看成模块的集合,只要一个文件夹下面有个__init__.py文件,那么这个文件夹就可以看做是一个包。包下面的文件夹
还可以成为包(子包)。更进一步,多个较小的包可以聚合成一个较大的包,通过包这种结构,方便了类的管理和维护,也方便了用户的使用。比如
SQLAlchemy等都是以包的形式发布给用户的。
包和模块其实是很类似的东西,如果查看包的类型import SQLAlchemy
type(SQLAlchemy),可以看到其实也是<type
'module'>。import包的时候查找的路径也是sys.path。
包导入的过程和模块的基本一致,只是导入包的时候会执行此包目录下的__init__.py
而不是模块里面的语
句了。另外,如果只是单纯的导入包,而包的__init__.py中又没有明确的其他初始化操作,那么此包下面的模块是不会自动导入的。如:
PA
--__init__.py
--wave.py
--PB1
--__init__.py
--pb1_m.py
--PB2
--__init__.py
--pb2_m.py
__init__.py都为空,如果有以下程序:
- import sys
- import PA.wave #1
- import PA.PB1 #2
- import PA.PB1.pb1_m as m1 #3
-
- import PA.PB2.pb2_m #4
-
- PA.wave.getName() #5
-
- m1.getName() #6
- PA.PB2.pb2_m.getName() #7
当执行#1后,sys.modules会同时存在PA、PA.wave两个模块,此时可以调用PA.wave的任何类或函数了。但不能调用
PA.PB1(2)下的任何模块。当前Local中有了PA名字。
当执行#2后,只是将PA.PB1载入内存,sys.modules中会有PA、PA.wave、PA.PB1三个模块,但是PA.PB1下的任何
模块都没有自动载入内存,此时如果直接执行PA.PB1.pb1_m.getName()则会出错,因为PA.PB1中并没有pb1_m。当前Local
中还是只有PA名字,并没有PA.PB1名字。
当执行#3后,会将PA.PB1下的pb1_m载入内存,sys.modules中会有PA、PA.wave、PA.PB1、
PA.PB1.pb1_m四
个模块,此时可以执行PA.PB1.pb1_m.getName()了。由于使用了as,当前Local中除了PA名字,另外
添加了m1作为PA.PB1.pb1_m的别名。
当执行#4后,会将PA.PB2、PA.PB2.pb2_m载入内存,sys.modules中会有PA、PA.wave、PA.PB1、
PA.PB1.pb1_m、PA.PB2、PA.PB2.pb2_m六个模块。当前Local中还是只有PA、m1。
下面的#5,#6,#7都是可以正确运行的。
注意的是:如果PA.PB2.pb2_m想导入PA.PB1.pb1_m、PA.wave是可以直接成功的。最好是采用明确的导入路径,对
于./..相对导入路径还是不推荐用。
分享到:
相关推荐
讲解了python的import机制,从pyc与py区别,python词法分析,import种类等方面分析python的import
本文详述了Python的import机制,对于理解Python的运行机制很有帮助! 1.标准import: Python中所有加载到内存的模块都放在 sys.modules 。当 import 一个模块时首先会在这个列表中查找是否已经加载了此模块,如果...
主要介绍了Python中import机制的相关资料,帮助大家更好的理解和学习python,感兴趣的朋友可以了解下
使用sys.path.apped时,添加相对地址时,起始地址不是当前调用脚本或者模块的所在地址,而是当前的工作地址,比如命令为 ~/Documents/python/test$ python package/package1/module1_1.py,当前工作地址为~/...
在 Python 中使用 import 关键字来实现这个操作,但不是唯一的方法,还有 importlib.import_module() 和 __import__() 等。 也许你看到这个标题,会说我怎么会发这么基础的文章? 与此相反。恰恰我觉得这篇文章的...
在刚刚接触python时,我们会被其优美的格式、简洁的语法和无穷无尽的类库所震撼。在真正的将python应用到实际的项目中,你会遇到一些无法避免的问题。...本文主要讨论关于Python中import的机制与实现
在之前学习python设计模式(工厂模式实践篇),希望使用全局变量代替c++的宏完成服务自动注册功能时,遇到过一个问题,全局变量的定义和使用放在同一个可执行脚本中的问题
python面试常见问题1、“==”与is的区别2、list与tuple的区别3、python中list与dict4、局部变量和全局变量5、迭代器和生成器6、yield7、import过程8、python装饰器9、python特点(封装、继承、多态)10、垃圾回收...
import matplotlib.pyplot as plt import numpy as np def laplace_function(x,beta): result = (1/(2*beta)) * np.e**(-1*(np.abs(x)/beta)) return result #在-5到5之间等间隔的取10000个数 x = np.linspace(-5,...
Numba通过及时编译机制(JIT)优化Python代码,Numba可以针对本机的硬件环境进行优化,同时支持CPU和GPU的优化,并且可以和Numpy集成,使Python代码可以在GPU上运行,只需在函数上方加上相关的指令标记, ...
8.2 导入模块: 学习import语句 112 8.3 编写自定义模块 115 8.4 模块的搜索路径 117 8.5 Python的包 123 8.6 Python第三方库(模块)下载 128 九、文件IO编程 130 9.1 Python文件操作函数介绍 130 9.2 操作文件的一般...
已经开发了一个 python 包,用于根据先前的技能排名计算预期的胜利概率,并在结果之后更新排名。 from elosports.elo import Elo eloLeague = Elo(k = 20) eloLeague.addPlayer("Daniel", rating = 1600) eloLeague...
* [24 Python垃圾回收机制](#24-python垃圾回收机制) * [1 引⽤计数](#1-引⽤计数) * [2 标记-清除机制](#2-标记-清除机制) * [3 分代技术](#3-分代技术) * [25 Python的List](#25-python的list) * [26 Python...
Python的__import__方法可以动态地加载Python文件,即以某个py脚本的文件名作为__import__的参数,在程序运行的时候加载py脚本程序模块。对应的import关键字则是静态加载依赖的py模块。 描述 __import__() 函数用于...
Python语言特性 1 Python的函数参数传递 ...24 Python垃圾回收机制 1 引用计数 2 标记-清除机制 3 分代技术 25 Python的List 26 Python的is 27 read,readline和readlines 28 Python2和3的区别 29 super ini