Python入门-Python中的包,impot用法 import解释 环境变量
目录
pycharm add content roots to PYTHONPATH
编辑 Add source roots to PYTHONPATH
首先看
set PYTHONPATH=c:\myproject;c:\myproject\mylib是在命令行输入。 ide 怎么设置呢


import
import a 是绝对导入
import 不是“复制粘贴代码”,而是:
1. 在 sys.path 中查找有没有 a 这个模块或包;
2. 找到后,执行模块文件或包/__init__.py 一遍(如果有),创建一个模块对象;
3. 把这个模块对象缓存到 sys.modules(后面在到导入直接复用);
4. 在当前作用域绑定名字 a 指向这个模块对象。
- 如果 a 是模块 a.py:执行 a.py 顶层代码一遍;
- 如果 a 是包且有 __init__.py:执行 __init__.py,一切 a.xx 都来自 __init__.py;
- 如果 a 是目录但没有 __init__.py(Python3):
- a 会变成一个 “命名空间包”;
- 不执行任何初始化代码,但仍然创建模块对象 a,
如果a下没有__init__.py,
-
没有执行任何
__init__.py(因为压根没有); -
有
a.__path__、a.__spec__等属性 -
因为没有
__init__.py,所以: -
不会有包级别的初始化逻辑;
-
也没地方在包里写变量/函数(你没法在
a/__init__.py里写东西)。
只是建一个没有初始化代码的“空壳包对象”
a是模块




a是包




现在的 Python 3 里,目录没有 __init__.py 也可以当包(namespace package)用,可以 from a import b;
但不能在包里做初始化,也不能写包级内容

import a.b
import a.b
1)先导入 a,在 sys.path 中查找:
- 找到 a.py → a 是普通模块
- 找到目录 a/:
- 有 a/__init__.py → 普通包,执行 __init__.py
- 没有 __init__.py → 命名空间包(PEP 420),不执行任何文件导入完成后,将模块/包对象放入 sys.modules['a']。
2)再导入子模块 a.b:
要求 a 必须是包(即拥有 __path__):
- 普通包 ✅
- 命名空间包 ✅
- 普通模块 a.py ❌Python 会在 a.__path__ 指向的路径中,
按 import 规则查找名为 b 的子模块,
b 可以是:
- a/b.py ->普通模块,直接执行
- a/b/__init__.py ->普通包,执行__init__.py
- a/b/(命名空间包)→ 命名空间包(PEP 420),不执行任何文件
- 或由 import hook 提供的模块找到后,加载并执行该模块。
3)将子模块缓存到 sys.modules['a.b']。
4)并将其绑定到包对象 a 上:
a.b = <module a.b>注意:当前作用域不会直接得到名字 b,
只能通过 a.b 访问。
例如访问b.py里的foo()就要写 a.b.foo()点号链里,除最后一段外,中间每一段都必须是包

from xxx import yyy
xxx: 点号链里,除最后一段外,中间每一段都必须是包
from a import b
from a import b
它做的事情可以按下面几步理解:
-
先找到并加载
a(绝对导入)-
在
sys.path里的各个目录下查有没有叫a的模块/包:-
找
a.py→ 模块 -
找目录
a/(有或没有__init__.py)→ 包 / 命名空间包
-
-
如果是模块
a.py:执行a.py顶层代码,得到模块对象a -
如果是包
a/且有__init__.py:执行a/__init__.py,得到包对象a -
如果是包
a/没有__init__.py:创建“命名空间包”对象a -
把这个
a放进sys.modules缓存(以后再导入直接复用)
-
-
在
a里面找名字b-
如果
a是模块/包,先看它有没有属性b(在a.py或a/__init__.py里定义/赋值的) -
如果
a是包,会尝试把b当作 子模块或子包 导入:-
比如存在
a/b.py,就会导入子模块a.b,然后把这个模块对象当作 -
普通包:执行__init__.py。命名空间包:不执行任何文件
-
-
-
在当前模块的命名空间里绑定名字
b-
最终效果是:当前文件里多了一个名字
b -
这个
b要么是:-
a的一个属性(函数、类、变量…),要么是 -
子模块
a.b这个模块对象本身
-
-


from a.b import c
点号链里,除最后一段外,中间每一段都必须是包
第一步:找到并加载 a
- 在 sys.path 里找顶层名字 a:
- 找到 a.py → 普通模块
- 找到目录 a/ 且有 __init__.py → 普通包:
* 执行 a/__init__.py 一遍
* 创建包模块对象 a
- 找到目录 a/ 但没有 __init__.py → 命名空间包:
* 不执行任何文件
* 创建命名空间包对象 a
- 最后把 a 放进 sys.modules['a']。
- a是普通模块 -->报错
- a是普通包/命名空间包,在
a下面找到并加载ba/b.py存在- 加载
a/b.py
执行它的顶层代码
创建模块对象
a.b放入
sys.modules['a.b']
a/b/目录存在,但里面没有__init__.py(Python 3)
→a.b是一个命名空间子包(namespace package)
不执行任何文件(因为没有
__init__.py可执行)但仍然创建一个“命名空间包”对象
a.b,带有__path__放入
sys.modules['a.b']
a/b/__init__.py存在
- →
a.b是一个普通子包加载
a/b/__init__.py执行其中的代码
创建包模块对象
a.b放入
sys.modules['a.b']:导入c:
1、b是包
1、c是__init__.py里的内容
2、c是普通模块,执行
3、 c是普通包 -->执行__init__.py,c是命名空间包,什么也不执行
2、b是模块,c是b里面的内容
导入只执行一次

import a, a里写 import b



循环导入
如果 a 和 b 互相 import,就可能出现“其中一个模块还没初始化完,另一个就想用它的属性”的问题,这就是循环导入坑,需要通过调整 import 位置或拆模块来解决。





绝对导入
import xxx
from xx import xx都是绝对导入。
都是根据sys.path去找。
-
import a
→ 在sys.path路径里找一个叫a的模块或包,加载后把它命名为a。
a是模块就是把a模块顶层代码执行一遍
a是包时就是把__init__.py的代码执行一遍,然后a.xx,xx来自__init__.py




现在的 Python 3 里,目录没有 __init__.py 也可以当包(namespace package)用,可以 from a import b;
但不能在包里做初始化,也不能写包级内容



-
from a import b
→ 先像上面那样找到/加载模块或包a,然后从a里再拿出名字b(属性或子模块)放到当前命名空间。
---------------------------------------------------------
练习是否理解
对于按照第一篇博客讲的,对于下面这一个博客,还是会不明白,不要紧先大体看一遍
Python中import的用法总结_import在python中的用法-CSDN博客
对于这个错误

在 Python 3 里,
import xxx默认是绝对导入。
你运行的是:
python main.py这时候,“当前工作目录(项目根目录)” 会被加到
sys.path里所以 Python 在执行
import cc时,会去sys.path里的各个目录下面找:
根目录下面找:有没有
cc.py或cc/__init__.py其它路径…(标准库、site-packages 等)
但你的
cc.py在branch/cc.py里,不在根目录,所以:顶层模块
cc并不存在,结果就是:ModuleNotFoundError: No module named 'cc'
为什么 bb.py 中的from . import cc 可以找到 。main.py在Pythonprojectt目录 此时.不应该是Pythonproject吗 ?


在
bb.py中,from . import cc的 “.” 表示的是 当前模块所属的包,也就是branch包,而不是根据运行的入口文件(main.py)来决定的。从当前模块所在的包导入cc
这个“属于哪个包”的信息来自模块运行时的一个变量:
__package__
那为什么 “.” 是相对于 branch,不是运行的入口文件的目录?
这是 Python 的导入机制中的一个关键点:
Python 中的每个模块都有一个特殊变量
__package__。当你运行
main.py,Python 会导入 branch.bb,此时bb.py的__package__ = 'branch'。所以
from . import cc会被理解为:from branch import cc。

解释





不能直接运行含相对导入的模块!
python -m
通过 -m 参数 执行某个模块,那么 当前工作目录 会被加到 sys.path 中作为模块搜索路径。

-m 后面要的是“模块名”,不是文件路径,也不能用相对名(如 .\main.py)
python -m X的规则是:
先按
import X的方式找到模块 X如果 X 是普通模块(文件
X.py)→ 执行这个文件如果 X 是包(目录
X/)→ 执行X/__main__.py,有X/__main__.py→ 就执行它,没有X/__main__.py→ 直接报错【顺便区分一下:X/__init__.py是“导入包时初始化用的”X/__main__.py是“把包当程序运行时的入口”】
例1:
情况 1:
a是普通模块
找到
a.py→ 执行a.py情况 2:
a是包目录a/
如果是普通包(有
a/__init__.py)→ 会先执行a/__init__.py(导入/初始化包)如果是命名空间包(无
__init__.py)→ 不执行__init__(因为没有)然后去找并执行入口:执行
a/__main__.py
没有
a/__main__.py→ 报错(包不能直接-m运行)
例2:
python -m a.b
先导入包
a
a/__init__.py存在(普通包)→ 执行a/__init__.py不存在(命名空间包)→ 不执行初始化文件
定位目标模块
a.b并运行
如果是普通模块:存在
a/b.py
→ 执行a/b.py如果是包:存在目录
a/b/
若有
a/b/__init__.py(普通包)→ 通常会先执行a/b/__init__.py(导入包初始化)然后执行入口:
a/b/__main__.py
没有
__main__.py→ 报错
例3:
python -m a.b.c
1)定位并导入
aPython 先按
import a的规则在sys.path里找:
若找到
a.py(普通模块)
→ 报错:因为普通模块a不能再有子模块a.b
(常见报错:No module named 'a.b'; 'a' is not a package')若找到目录
a/(包或命名空间包)
若有
a/__init__.py(普通包)→ 执行a/__init__.py,并得到包对象a若没有
a/__init__.py(命名空间包)→ 创建命名空间包对象a(不执行文件)并把结果缓存到
sys.modules['a']。
2)定位并导入
a.b(这里 必须是包)在
a的包搜索路径(a.__path__)下找:
若找到
a/b.py(普通模块)
→ 报错:a.b不是包,不能再继续找a.b.c
报错形式通常是:No module named 'a.b.c'; 'a.b' is not a package若找到目录
a/b/(包或命名空间包)
若有
a/b/__init__.py(普通包)→ 执行a/b/__init__.py若没有
a/b/__init__.py(命名空间包)→ 创建命名空间包对象a.b(不执行文件)并缓存到
sys.modules['a.b'],同时让a.b可用(挂到a上)。
3)运行目标模块
a.b.c现在开始处理
c(最后一段可以是模块文件,也可以是包):情况 A:
c是普通模块文件
若存在
a/b/c.py
→ 执行a/b/c.py(这就是-m指定的目标模块被执行)并缓存到
sys.modules['a.b.c']。情况 B:
c是包目录
若存在目录
a/b/c/
若有
a/b/c/__init__.py(普通包)→ 可能会先执行它(导入初始化)然后必须有入口文件:执行
a/b/c/__main__.py
如果没有
a/b/c/__main__.py→ 报错(包不能作为-m目标直接运行)
python -m main
(.venv) PS D:\zhouj\Documents\Pythontest\Project1> python -m main




python -m Project1.main
cd Pythontest python -m Project1.main











Pycharm 如何寻找导入的模块?
在pycharm 可以运行 但是在命令行不可以运行 因为pycharmsys.path有项目根目录。
pycharm add content roots to PYTHONPATH
Add source roots to PYTHONPATH

#Python中的包
#包(python package)是一个分层次的目录(directory)结构,它将一组功能相近的模块组织在一个目录下
#作用:1.代码规范,2.避免模块名称冲突
#包与目录的区别
#包含__init__.py文件的目录称为包
#目录通常不包含__init__.py文件
#包的导入
#import 包名.模块名
#在demo中导入包:demo2中的模块:modelA
import demo2.modelA
print(demo2.modelA.a)
import demo2.modelA as s#导入包:demo2中的模块:modelA起别名为s
#s是demo2.modelA的别名
print(s.a)
###############################################
'''导入带有包的模块时的注意事项
使用import方式进行导入时,只能根报名或模块名
import clc
import demo2
使用from impor导入时可以导入包,模块,函数,变量等
from demo2 import modelA导入包demo2中的模块a
from demo2.modelA import a导入包demo2中的模块modelA的a
'''
环境变量
python -m 的作用是:让 Python 按“模块名”去运行代码,而不是按“文件路径”去运行代码。-m 里的 m 可以理解成 module,也就是模块
python -m 的作用是:
用当前 Python 解释器,按照模块名去当前环境的搜索路径中查找并运行一个模块或包。这个模块/包可以是:
1. 你自己项目里的模块;
2. Python 标准库模块;
3. 虚拟环境 site-packages 里安装的第三方包;
4. 其中一些第三方包提供命令行入口,因此也可以当作第三方工具使用。
作用 1:运行你自己项目里的模块


作用 2:运行已经安装好的第三方模块或包
python -m还有一个很常见的作用:保证用的是当前 Python 环境让当前 python 去它自己的环境里找对应模块并运行
python -m可以运行当前 Python 环境中能找到的 模块或包;其中有些包刚好提供了命令行功能,所以看起来像是在运行“第三方工具”
























更多推荐
所有评论(0)