文件夹结构
(base) t@t-virtual-machine:~/PycharmProjects/importLeaning$ tree -L 2 . ├── folder01 │ ├── in01.py │ └── inMain01.py ├── outMain01.py ├── outMain02.py ├── package02 │ ├── in02.py │ ├── __init__.py │ └── inMain02.py └── venv
1 常规情况(完整路径+文件名)
1.1 文件夹(folder)
in01.py
def fun_in01():
print("This is in01.py!")
print("The abs_path is: importLearning -> folder01 -> in01.py -> fun_in01()")
inMain01.py(与in01.py在同一个文件夹)
from in01 import fun_in01 # 正常
fun_in01()
outMain01.py(与in01.py不在同一文件夹)
from folder01.in01 import fun_in01 # 正常
fun_in01()
文件夹正常调用方法
同
文件夹内部调用(inMain01.py调用in01.py中的函数)不同
文件夹之间调用(outMain01.py调用in01.py中的函数)
1.2 包(package)
in02.py
def fun_in02():
print("This is in02.py!")
print("The abs_path is: importLearning -> package02 -> in02.py -> fun_in02()")
__init__.py
def fun_init():
print("This is __init__.py!")
print("The abs_path is: importLearning -> package02 -> __init__.py -> fun_init()")
inMain02.py(与in02.py,__init__.py在同一个包)
from in02 import fun_in02 # 正常
fun_in02()
# --------------------------------------
from __init__ import fun_init # 正常
fun_init()
outMain02.py(与in02.py,__init__.py不在同一包)
from package02.in02 import fun_in02 # 正常
fun_in02()
# --------------------------------------
from package02.__init__ import fun_init # 正常
fun_init()
包正常调用方法
同
包内部调用(inMain02.py调用in02.py,__init__.py中的函数)不同
包之间调用(outMain02.py调用in02.py,__init__.py中的函数)
1.3 总结
在同一个包/文件夹时:
from脚本名import函数名不在同一个包/文件夹时:
from包名[文件夹名].脚本名import函数名
2 常用情况(不完整的路径/文件名)
inMain02.py(调用__init__.py在同一个包)
正常情况
# inMain02.py
from package02 import fun_init # 注意,此时直接用包名,没有.后缀
fun_init()
异常①
# inMain02.py
# ImportError: cannot import name 'fun_in02' from 'package02' (/home/t/PycharmProjects/importLeaning/package02/__init__.py)
from package02 import fun_in02
fun_in02()
2.1 解析
从异常①代码和正常情况对比,可以发现包名和包内的__init__.py有特殊联系:
可以通过包名(省去
.脚本名)的方式,即from 包名[文件夹名].脚本名import 函数名,导入包内__init__.py文件中的函数;但,不能通过这个方式导入其他
.py文件中的函数。
异常 ②
# inMain02.py
from . import fun_init # ImportError: attempted relative import with no known parent package
fun_init()
异常 ③
# inMain02.py
from .__init__ import fun_init # ImportError: attempted relative import with no known parent package
fun_init()
outMain02.py(调用__init__.py不在同一个包)
正常
# outMain02.py
from package02 import fun_init # 注意,此时直接用包名,没有.后缀
fun_init()
异常② -> 正常
# inMain02.py (异常②)
from . import fun_init # ImportError: attempted relative import with no known parent package
fun_init()
# outMain02.py
from package02 import inMain02
异常③ -> 正常
# inMain02.py (异常③)
from .__init__ import fun_init # ImportError: attempted relative import with no known parent package
fun_init()
# outMain02.py
from package02 import inMain02
2.2 解析
异常②,异常③提示的错误信息都是:no known parent package (没有已知的父包)
解决方法是:
在文件(
outMain02.py)中from package02 import inMain02这一句代码,将
package02包导入了进来,而此包就是(
__init__.py)所在的包。
★ 解决了(inMain02.py)文件中no known parent package的问题。
综合执行(正常):
outMain02.py
from package02 import inMain02
inMain02.py单独执行会报错异常② & 异常③
from .__init__ import fun_init异常② orfrom . import fun_init异常③
fun_init()
2.3 最后比较
# ---------------------------------------------------
# outMain02.py
# (异常)ImportError: cannot import name 'fun_in02' from 'package02' (/home/t/PycharmProjects/importLeaning/package02/__init__.py)
from package02 import fun_in02 # fun_in02是在in02.py文件中的
fun_in02()
# ---------------------------------------------------
# outMain02.py
# (正常)
from package02 import fun_init # fun_init是在__init__.py文件中的
fun_init()
3 探究__init__.py的特殊性
既然
包与__init__.py之间有特殊性,那么具体特殊的地方在哪里?代码全清空,只留下包
package02, 及其内部文件.py文件,包括__init__.py,in02.py,inMain02.py.
3.1 各个文件初始内容
__init__.py
def fun_init():
print("This is __init__.py!")
print("The abs_path is: importLearning -> package02 -> __init__.py -> fun_init()")
in02.py
def fun_in02():
print("This is in02.py!")
print("The abs_path is: importLearning -> package02 -> in02.py -> fun_in02()")
inMain02.py
from package02.__init__ import fun_init # 正常
fun_init()
from package02 import fun_init # 正常(<-测试1)
fun_init()
from . import fun_init # 异常②
fun_init()
from .__init__ import fun_init # 异常③
fun_init()
3.2 测试1
原版
inMain02.py
from package02 import fun_init # 正常(<-测试1)
fun_init()
改版1 - 报错
# inMain02.py
# ImportError: cannot import name 'fun_in02' from 'package02' (/home/t/PycharmProjects/importLeaning/package02/__init__.py)
from package02 import fun_in02
fun_in02()
改版2
# --------------------------------------------------
# inMain02.py
# 改版1原代码,不动
from package02 import fun_in02
fun_in02()
# --------------------------------------------------
# __init__.py
# 修改文件__init__.py,即可配合改版2 - inMain02.py 实现正常输出
from .in02 import fun_in02 # 修改地方:增加此句
def fun_init():
print("This is __init__.py!")
print("The abs_path is: importLearning -> package02 -> __init__.py -> fun_init()")
3.3 分析
文件结构为: 包
package02, 及其内部文件.py文件,包括__init__.py,in02.py,inMain02.py.在
__init__.py中,将同级文件in02.py中的函数导入,即可调用该函数。
3.4 测试2
改版3
# inMain02.py
# 改版2的 __init__.py原代码,不动;重新修改inMain02.py,也可实现正常输出
import package02
package02.fun_in02()
3.5 总结正常输出的两种情况
# [通用] in02.py
def fun_in02():
print("This is in02.py!")
print("The abs_path is: importLearning -> package02 -> in02.py -> fun_in02()")
# [通用] __init__.py
from .in02 import fun_in02 # 修改地方:增加此句
def fun_init():
print("This is __init__.py!")
print("The abs_path is: importLearning -> package02 -> __init__.py -> fun_init()")
# 第一种 inMain02.py
# from 包名 导入 函数名,即 导入包内的__init__.py文件添加的函数
from package02 import fun_in02
fun_in02()
# 第二种 inMain02.py
# import 包名,即 导入包内的__init__.py文件
import package02
package02.fun_in02()
4 总结
__init__.py文件,具有特殊性,可以通过from 包名 import 函数名进行调用;.py文件若含有
from . import 导包或导入函数的情况,无法在该文件下正常执行,而父模块被外部加载时可以正常被使用。重点:通过操作
__init__.py文件,即,在其内部导入包,可以给包本身增加attribute.
三种
import的方式import 包名,实际上是import包内的__init__.pyimport package02,就是把package02包中的__init__.py包含的内容导入,所以,此时__init__.py内部应该已经添加了待调用的函数。
from 脚本名(.py文件名) import 函数名e.g.,
from package02.in02 import fun_in02e.g.,
from .in02 import fun_in02(被导入的脚本和目标脚本在同一文件夹,可省略包名)
from 包名 import 函数名和第二种相同,只是此时的脚本是__init__.pyfrom package02 import fun_in02
目录
注释:以上内容为本人自学过程的记录,可能有所欠缺或错误,欢迎随时联系,共同探讨。