python package 之间的调用
python 解释器搜索package 模块过程
模块:每一个python文件都是一个模块。
当执行import module时,解释器会根据下面的搜索路径,搜索module1.py文件。
1) 当前工作目录
2) PYTHONPATH中的目录
3) Python安装目录 (/usr/local/lib/python)
事实上,模块搜索是在保存在sys.path这个全局变量中的目录列表中进行搜索。
package是模块的集合,每一个Package的根目录下面都应当有一个__init__.py 文件。当解释器发现目录下有这个文件时,他就会认为这是一个Package,而不是一个普通的目录。
示例:通过两种方法来实现包机制,主要区别在于是否在 __init__.py 中写入模块导入语句
目录结构如下:
[root@dev home]# tree package_transfer/ package_transfer/ ├── demo.py ├── __init__.py ├── package01 │ ├── classOne.py │ └── __init__.py └── package02 ├── classTwo.py └── __init__.py
第一种调用方式 : __init__.py 是一个空白文件
1.在主入口文件里面调用。
classOne.py 内容如下:
from package02.classTwo import classTwo class classOne: def __init__(self): self.name = "class one" def printInfo(self): print("i am class One!")
classTwo.py 内容如下:
class classTwo: def __init__(self): self.name = "class two" def printInfo(self): print("i am class two!")
主入口文件:demo.py 内容如下
from package01.classOne import classOne from package02.classTwo import classTwo if __name__ == "__main__": c1 = classOne() c1.printInfo() c2 = classTwo() c2.printInfo() # 运行结果: # i am class One! # i am class two!
因为 此时的demo.py 文件和 package01,package02 在同一层目录下,因此,可以直接调用包下面的模块方法。
2.加入 classOne.py 要去调用 package02 下的文件 classTwo 里面的方法。
import os,sys BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) #这里是把顶层目录加入到python的环境变量中。 sys.path.append(BASE_DIR) from package02.classTwo import classTwo class classOne: def __init__(self): self.name = "class one" def printInfo(self): print("i am class One!") if __name__ == "__main__": c2 = classTwo() c2.printInfo() # 运行结果: # i am class two!
第二种调用方式:在__init__.py 下面写入包的信息。
还是上面的目录和内容:
在 packge01/__init__.py 中添加:
import sys,os BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(BASE_DIR) from package01.classOne import classOne
在 packge02/__init__.py 中添加:
import sys,os BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(BASE_DIR) from package02.classTwo import classTwo
在 demo.py 文件中就可以这样写:
import package01 import package02 if __name__ == "__main__": c1 = package01.classOne() c1.printInfo() c2 = package02.classTwo() c2.printInfo() # 运行结果: # i am class One! # i am class two!
还可以这样导入:
from package01 import * from package02 import * if __name__ == "__main__": c1 = classOne() c1.printInfo() c2 = classTwo() c2.printInfo() # 执行结果 # i am class One! # i am class two!
如果不在上面的 __init__.py 文件中写入信息。如果直接导入,那么会报如下错误:
import package01 import package02 if __name__ == "__main__": c1 = package01.classOne() c1.printInfo() c2 = package02.classTwo() c2.printInfo() # 运行结果: # Traceback (most recent call last): # File "D:/gitcode/...../package_transfer/demo.py", line 21, in <module> # c1 = package01.classOne() # AttributeError: module 'package01' has no attribute 'classOne'
记忆:所有的模块的引入,在__init__.py 里面的路径应该写到当前project 的顶层目录,这样在调用的时候 就能够清晰明了的导入自己想要导入的模块。