介绍
类似 js 的 es module
导入模块
python
# [from 模块名称] import [模块|类|变量|常量|函数|*(所有内容)] as 别名
# 1.导入整个模块
import 模块名称
# 2.导入模块的某个功能
from 模块名称 import 变量|函数|类等
# 3.导入整个模块的所有内容
from 模块名称 import *
# 4. 导入整个模块并重新命名
import 模块名称 as 别名
# 5.导入某个模块的功能并重新命名
from 模块名称 import 功能名 as 别名python
from random import randint as get_random_number
rand_num = get_random_number(1, 9)
print(rand_num)标准库模块
所谓标准库模块, 就是 python 解释器自带的模块, 只要安装了 python 就可以直接导入使用的模块 查看python 编译器标准库文档
python
import random
print(random.randint())内置模块 __builtins__
这是标准库模块中特殊的一个模块, 它存放了一些 特别常用的 函数和类, 比如: print range len 等等, 解释器会自动的导入这个模块
python
# 我并没有手动 import builtins
# 就可以直接使用 __builtins__ 变量和 dir print 方法
for item in dir(__builtins__):
print(f"{item} 来自于 builtins 模块")python
import __builtin__
for item in dir(__builtin__):
print(f"{item} 来自于 __builtin__ 模块")自定义模块
- 创建文件
mod1并输入以下内容
python
def mod1_test():
print("mod1_test excuted")- 在
main.py中导入
python
# 这个 模块名就是文件名(不包含.py 后缀) [mod1.py]
import mod1
mod1.mod1_test()__name__ 常量
当直接执行的时候, __name__ 的值为 __main__, 当导入的时候, __name__ 的值就不是 __main__
python
# mod1.py 内容如下:
def mod1_test():
print("mod1_test excuted")
# 使用 python mod1.py 直接运行会进入 if 中的代码
# 当在 main.py 中导入的时候 mod1.py 的时候不会执行
if __name__ == '__main__':
mod1_test()自定义包(package)
什么是 python package
包的本质就是一个目录, 并且含有 __init__.py 这个文件, 这个目录下可以有多个模块, 并且通过 __init__.py 来管理导出行为, 那么这个目录就是 python package
sh
# 创建对应文件
mkdir mypkg
touch mypkg/__init__.py
touch mypkg/mod1.py
touch mypkg/mod2.py文件中代码如下:
python
# 执行 python main.py 查看结果
from mypkg import mod1
from mypkg import mod2
mod1.f1()
mod2.f2()python
# 这个文件可以为空, 但是文件必须存在python
def f1():
print("我是 mod1 中的 f1 方法")python
def f2():
print("我是 mod2 中的 f2 方法")导包的底层逻辑
1.第一次导入
- 将自己当前的命名空间中的代码执行
- 创建模块对象, 并将模块内所有的变量绑定到模块对象上
- 在 import 语句的位置, 引入被导入的变量到当前的命名空间
2.第n次导入
只要导入过一次, 那么后面的导入语句就只会执行第三个步骤
python
.
├── README.md
├── main.py
├── pkg1
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-312.pyc
│ │ └── example.cpython-312.pyc
│ └── example.py
├── pyproject.toml
└── uv.lock
3 directories, 8 filespython
from pkg1 import example_inst
# 第一次导入,执行 __init__.py 控制台输出: "__init__ executed"
import pkg1 as pkg2
import pkg1 as pkg3
# 后续导入不再执行 __init__.py, 只是将包中的变量导入到当前命名空间
def main():
example_inst.test()
pkg2.example_inst.test()
pkg3.example_inst.test()
if __name__ == "__main__":
main()
# 执行 uv run ./main.py 的输出如下:
# __init__ executed 说明 __init__ 执行了
# Example class init 说明 __init__ 执行了
# 没有多次输出 "__init__ executed", 说明只执行了一次
# Example test method exteuted, 说明: example_inst.test() 执行了
# Example test method exteuted, 说明: pkg2.example_inst.test() 执行了
# Example test method exteuted, 说明: pkg3.example_inst.test() 执行了python
from .example import Example
print("__init__ executed")
# example 类的实例对象
example_inst = Example()python
class Example:
def __init__(self):
print("Example class init")
def test(self):
print("Example test method exteuted")sys.path 对导包的影响
通过代码我们发现, Python 导包的语句并不是类似js那样直接基于操作系统路径的, 那么他是如何找到这些代码的呢?
- 首先去找
builtins模块, 看是否有 - 然后去 sys.path 这个目录列表中去找
python
import sys
print(sys.path)
# 控制台输出如下:
# [
# '/Users/secret/codes/py-fastapi-demo',
# '/Users/secret/.local/share/uv/python/cpython-3.12.12-macos-x86_64-none/lib/python312.zip',
# '/Users/secret/.local/share/uv/python/cpython-3.12.12-macos-x86_64-none/lib/python3.12',
# '/Users/secret/.local/share/uv/python/cpython-3.12.12-macos-x86_64-none/lib/python3.12/lib-dynload',
# '/Users/secret/codes/py-fastapi-demo/.venv/lib/python3.12/site-packages',
# ]
print(type(sys.path))
# 控制台输出如下:
# <class 'list'>
# 我发现 sys.path 是一个 list
# 也就说可以手动修改这个 sys.path 来控制导包的行为修改 sys.path 控制导包语句的查找列表
假设现在的项目结构是这样的:
.
├── pyproject.toml
├── src
│ ├── main.py # 主入口文件
│ └── shared
│ └── tools.py
├── test.py
└── uv.lock
3 directories, 7 files如果想要在 src/main.py 中导入 /test.py 和 src/shared/tools.py 可以这样做:
python
#### src/main.py
import sys
from os import path
# 将当前文件所在的目录添加到 sys.path 中
script_path = path.dirname(path.abspath(__file__));
sys.path.append(script_path)
# 将当前文件所在目录的父级目录添加到 sys.path 中
sys.path.append(path.dirname(script_path))
# 注: 这些导入语句必须写在修改 sys.path 的语句之后
from test import test_fn1 # 导入 test.py 中的内容
from src.shared.tools import tools_fn1 # 导入 src/shard/tools.py 中的内容安装第三方包
类似 node.js 的安装第三方包, 只不过 node.js 包管理的工具叫 npm 而 python 的包管理工具 pip
sh
# 已经安装的包
pip list
# 安装包
pip install numpy
# 删除已经安装的包
pip uninstall numpy
# 去 https://pypi.org 搜索某个包
pip search numpy
# 查看帮助
pip --help
# 导出安装的包列表
pip freeze > requirments.txt设置包管理器源
sh
pip install numpy -i https://pypi.tuni.tsinghua.edu.cn/simplesh
# 修改 ~/.pip/pip.conf 文件(没有就创建), 输入以下内容
[global]
index-url = https://pypi.tuni.tsinghua.edu.cn/simplesh
阿里云: http://mirrors.aliyun.com/pypi/simple/
中国科技大学: https://pypi.mirrors.ustc.edu.cn/simple/
豆瓣: http://pypi.douban.com/simple/
清华大学: https://pypi.tuna.tsinghua.edu.cn/simple/
中国科学技术大学: http://pypi.mirrors.ustc.edu.cn/simple/