1. 虚拟环境机理
在 Conda 环境中,activate.d
目录用于存放当激活环境时自动执行的脚本。这些脚本可以是 shell 脚本(如 .sh
文件)或批处理脚本(如 .bat
文件),具体取决于你的操作系统。
cd ~/anaconda3/envs/myenv/etc/conda/activate.d
Conda 环境的激活过程通常会执行 activate.d
目录下的所有脚本,然后,每次激活该 Conda 环境时,你的自定义脚本就会被执行。
gdp@gdp:~/anaconda3/envs/myenv/etc/conda/activate.d$ ls
libglib_activate.sh qt-main_activate.sh
可以自己添加一个脚本文件env_vars.sh,内容为:
export LD_LIBRARY_PATH=~/anaconda3/envs/myenv/lib:$LD_LIBRARY_PATH
添加了路径依赖
2. 当前工作目录 和 Python模块导入机制
有时python的site-packages下面的包导出不成功/home/gdp/anaconda3/envs/myenv/lib/python3.8/site-packages/fbx/,切换到cd ..目录下,可以import,但是内容是空的。
Python的模块搜索路径 (sys.path
)
当你在 site-packages/fbx
目录下直接运行 Python 时,当前目录 (~/anaconda3/envs/myenv/lib/python3.8/site-packages/fbx
) 会被自动添加到 sys.path
的最前面。日常可以显式指定模块路径,在代码中手动调整 sys.path
:
import sys
# 确保 site-packages 路径在 sys.path 中,且优先级高于当前目录
sys.path.insert(0, "/home/gdp/anaconda3/envs/myenv/lib/python3.8/site-packages")
from fbx import * # 此时应正常导入
检查 fbx
包安装完整性
fbx
模块的安装目录包含FbxCommon.py fbxsip.so fbx.so文件,通常应包含 __init__.py
文件
-
__init__.py
的核心功能
定义包的初始化逻辑,控制模块的导入行为。此处需要实现:-
确保
fbx.so
和fbxsip.so
能够正确加载。 -
暴露
FbxCommon.py
中的工具函数或类。 -
解决路径冲突问题(避免因当前目录干扰模块搜索)。
-
__init__.py文件内容,一般如下,从*.so库中导入文件,这样导入后,模块内容就不会是空的
*.so文件可以直接from 文件名 import *
# ~/anaconda3/envs/myenv/lib/python3.8/site-packages/fbx/__init__.py
import sys
import os
# 确保优先从当前包的目录加载模块(避免同名模块冲突)
_package_dir = os.path.dirname(__file__)
if _package_dir in sys.path:
sys.path.remove(_package_dir)
sys.path.insert(0, os.path.dirname(_package_dir)) # 确保父目录在路径中
# 导入核心模块
from .fbx import * # 导入 fbx.so 的所有符号
from .fbxsip import * # 导入 fbxsip.so 的所有符号
# 导入辅助工具模块(可选)
from .FbxCommon import * # 导入 FbxCommon.py 的所有工具函数/类
# 清理临时变量(可选)
del sys, os, _package_dir
3. 运行找不到依赖
例如:from .fbx import * # 导入 fbx.so 的所有符号 ImportError: /home/gdp/anaconda3/envs/myenv/lib/libstdc++.so.6: version `GLIBCXX_3.4.30' not found (required by /home/gdp/anaconda3/envs/myenv/lib/python3.8/site-packages/fbx/fbx.so)
根据错误信息,fbx.so
需要 GLIBCXX_3.4.30
,但当前 Anaconda 环境中的 libstdc++.so.6
不包含此版本
1. 升级 Conda 环境中的 libstdcxx-ng
在 Conda 环境中安装或更新 libstdcxx-ng
(包含较新的 libstdc++.so.6
):
# 激活环境
conda activate myenv
# 更新 libstdcxx-ng(指定版本)
conda install -c conda-forge libstdcxx-ng=11 -y
2. 验证 GLIBCXX
版本
检查当前环境中的 libstdc++.so.6
是否包含 GLIBCXX_3.4.30
:
# 查看支持的 GLIBCXX 版本
strings ~/anaconda3/envs/myenv/lib/libstdc++.so.6 | grep GLIBCXX
# 输出应包含以下内容:
GLIBCXX_3.4.30
GLIBCXX_3.4.31
...
Conda 环境中的 libstdc++
版本已无法满足,系统安装的 GCC 11+),可以绕过 Conda 的旧版本库
查找系统的 libstdc++.so.6
# 查找系统库路径
find /usr -name "libstdc++.so.6" 2>/dev/null
# 典型路径:/usr/lib/x86_64-linux-gnu/libstdc++.so.6
# 检查是否包含 GLIBCXX_3.4.30
strings /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | grep GLIBCXX_3.4.30
替换 Conda 环境的库文件
# 备份旧库
mv $CONDA_PREFIX/lib/libstdc++.so.6 $CONDA_PREFIX/lib/libstdc++.so.6.bak
# 创建符号链接指向系统库
ln -s /usr/lib/x86_64-linux-gnu/libstdc++.so.6 $CONDA_PREFIX/lib/libstdc++.so.6
4. .egg-link
文件, Python 的「开发模式安装」,pip install -e .
当用 pip install -e .
安装包时:
-
不复制代码到
site-packages
,而是创建一个.egg-link
文本文件 -
文件内容记录了你项目的绝对路径(如
/home/user/my_project
) -
Python 解释器导入包时,会通过这个文件「跳转」到你的项目目录读取代码
例子
-
你的项目结构:
my_project/
├── setup.py
└── my_package/
└── __init__.py # 里面写了个 print("Hello!")
-
执行
pip install -e .
后,site-packages
中会出现:my_package.egg-link # 内容:/home/user/my_project
-
此时在任意位置运行 Python:
python
import my_package # 会直接读取 /home/user/my_project/my_package 下的代码
-
修改
__init__.py
为print("Hi!")
,无需重新安装,再次导入就会生效
- 还会生成
easy-install.pth
文件,记录所有通过-e
模式安装的包 - 删除
.egg-link
和.pth
中的对应条目,相当于「取消直播」 - 生产环境不要用
-e
模式,因为路径依赖可能导致环境不一致
5. 模块导入的绝对导入和相对导入
核心规则总结
1. 运行文件(Top-level Script)
-
必须使用绝对导入:直接执行的脚本(如
python main.py
)中,若使用相对导入会报错。 -
原因:直接运行时,Python 将文件视为顶层模块(
__name__ = "__main__"
),无法识别包层级结构
2. 包内模块(Package Modules)
-
推荐使用相对导入:包内部的子模块相互引用时,优先使用相对导入(如
from . import module
)。 -
优势:避免硬编码包名,提升代码可维护性(包名变更时无需修改导入路径)
解释
绝对导入: 从项目根目录(顶层包)开始的完整路径导入。
from myapp.utils.logger import setup_logger # 根目录为 myapp
-
适用场景:顶层脚本(如
main.py
),跨包引用(如从app/core
导入app/utils
的模块),引用第三方库(如from flask import Flas
相对导入(Relative Import):
-
只能在包内模块中使用,不可用于顶层脚本710。
-
需通过
python -m package.module
运行(确保包结构被识别)
Tips: 优先使用绝对导入,尤其在大型项目中。包内模块使用相对导入,简化包内引用,避免硬编码包名。统一运行方式,包内模块通过 python -m 运行,确保包结构被正确识别。配置项目路径,若需跨包导入,可将根目录加入 sys.path
6. 在 sys.path
中添加项目根目录,实现跨包导入
问题描述:
my_project/
├── src/
│ ├── utils/
│ │ ├── math_tools.py # 包含数学工具函数
│ │ └── __init__.py
│ ├── models/
│ │ ├── user.py # 需要调用 math_tools
│ │ └── __init__.py
│ └── main.py # 主入口文件
└── requirements.txt
在 user.py
中想调用 math_tools.py
的函数:
# src/models/user.py
from utils.math_tools import calculate_discount # ❌ 错误:无法找到 utils 模块
def process_user():
discount = calculate_discount(100, 0.2)
print(f"折扣金额: {discount}")
解决方案:在入口文件添加根目录路径
# src/main.py
import os
import sys
# 关键代码:获取项目根目录路径并添加到 sys.path
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(project_root) # ✅ 现在可以找到所有子模块
# 然后导入其他模块
from models.user import process_user
if __name__ == "__main__":
process_user()
然后, user.py
无需修改即可运行
# 在项目根目录执行
cd my_project
python src/main.py
原理解释:
-
__file__
:获取当前文件路径(main.py
的路径) -
os.path.abspath(__file__)
:转为绝对路径(如/home/user/my_project/src/main.py
) -
os.path.dirname()
:-
第一次:得到
/home/user/my_project/src
-
第二次:得到
/home/user/my_project
(项目根目录)
-
-
sys.path.append()
:将此路径/home/user/my_project
加入 Python 的模块搜索路径,python会去按照名称搜索需要的模块。
7. 在 VSCode 中实现 MATLAB 风格的 Python 调试
如何使用vscode调试python代码,使得使用方法和matlab一样。即:可以一行一行的运行代码,运行后,可以在界面上查看变量的内容,运行结束变量内容不清零,保留在VARIABLE窗口中,最好运行后,可以自动打印变量的内容