在 Mac 正确的配置 python 环境还是件很头疼的事
pyenv
最终选择 pyenv/pyenv: Simple Python version management,不过还是要 brew install python
作为其他第三方工具的依赖。
- 确保安装了 xcode 命令行工具:
xcode-select --install
- 安装
pyenv
:brew install pyenv
-
安装编译依赖
brew install zlib sqlite export LDFLAGS="-L/usr/local/opt/zlib/lib -L/usr/local/opt/sqlite/lib" export CPPFLAGS="-I/usr/local/opt/zlib/include -I/usr/local/opt/sqlite/include"
- 安装 python
pyenv install 3.9.0
-
配置环境变量:
.zshenv
可以替换.zshrc
如果仅要在 shell 中生效的话,见 https://unix.stackexchange.com/a/71258echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshenv echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshenv echo -e 'if command -v pyenv 1>/dev/null 2>&1; then\n eval "$(pyenv init -)"\nfi' >> ~/.zshenv
pyenv global 3.9.0
设置默认的 python 版本pyenv local 3.8.6
对于特定目录使用 3.8.6,会在当前目录生成一个.python_version
文件
问题
openpose 编译 python api 不支持 pyenv,需自己手动指定。
阅读 pybind11/tools/FindPythonLibsNew.cmake 后发现,需要手动指定 PYTHON_EXECUTABLES,其他相应变量都会自动生成:
cmake -D BUILD_PYTHON:BOOL=ON -DPYTHON_EXECUTABLE=$HOME/.pyenv/versions/3.9.0/bin/python3.9 -S . -B ./build
FYI: FindPython — CMake 3.19.1 Documentation
虚拟环境
pyenv/pyenv-virtualenv: a pyenv plugin to manage virtualenv (a.k.a. python-virtualenv)
- git clone https://github.com/pyenv/pyenv-virtualenv.git $(pyenv root)/plugins/pyenv-virtualenv
- echo ‘eval “$(pyenv virtualenv-init -)”’ » ~/.zshrc
例子
比如 scikit-learn-0.23.2
不支持 python 3.9。创建一个 3.8.6 的虚拟环境
pyenv virtualenv 3.8.6 ml-venv
pyenv local ml-venv # 项目目录下执行
Emacs/lsp-mode
目前的方式还需要手动,选择虚拟环境的路径,先配置 pyvenv
(use-package pyvenv
:ensure t
:init
(setenv "WORKON_HOME" "~/.pyenv/versions")) ;;
然后可通过 pyvenv-workon 选择 pyenv 所有版本,选择后(或者直接 pyvenv-activate 目录),会将虚拟环境的python目录设置到环境变量 VIRTUAL_ENV。 lsp-mode 的 pyls 会读取这个变量,切换到这个 python 环境。通过这样曲线的形式来实现 lsp-mode 对虚拟环境的支持。
问题
环境 MacOS 11.0
安装 numpy
遇到 :#15947 (comment)
安装 scipy
遇到:https://stackoverflow.com/questions/41241468/error-pip-install-scipy
解决
brew install openblas
brew install gcc # 为了 gfortran,直接安装 gfortran 会报错 `[ld cannot find -lgcc_s](https://bugsfixes.blogspot.com/2016/02/mac-ld-library-not-found-for-lgccs104.html)`
brew install swig
建 ~/.numpy-site.cfg
:
[DEFAULT]
library_dirs = /usr/local/lib
include_dirs = /usr/local/include
[openblas]
libraries = openblas
library_dirs = /usr/local/opt/openblas/lib
include_dirs = /usr/local/opt/openblas/include
这是最重要的步骤,主要的报错就是找不到头文件和共享库
- 试过环境变量
CFLAGS
、LDFLAGS
、LD_LIBRARY_PATH
、LIBRARY_PATH
,不行 pip --global-option
shared libraries - python pip specify a library directory and an include directory - Stack Overflow,不起作用- 最终主要是参考了 homebrew 的 formula:numpy.rb、scipy.rb
scikit-image
brew install libomp
export CC=/usr/bin/clang
export CXX=/usr/bin/clang++
export CPPFLAGS="$CPPFLAGS -Xpreprocessor -fopenmp"
export CFLAGS="$CFLAGS -I/usr/local/opt/libomp/include -Wno-implicit-function-declaration"
export CXXFLAGS="$CXXFLAGS -I/usr/local/opt/libomp/include"
export LDFLAGS="$LDFLAGS -L/usr/local/opt/libomp/lib -lomp"
export DYLD_LIBRARY_PATH=/usr/local/opt/libomp/lib
tensorflow
Big Surf 需手动安装 whl No Matching Distribution Found for Tensorflow · Issue #31058 · tensorflow/tensorflow
安装 tensorflow 2.3.1,其依赖的 grpcio、h5py、scipy 版本太旧编译报错,也都需全部手动安装 whl。
其他方案
numpy 这样也能安装成功
brew install openblas
OPENBLAS="$(brew --prefix openblas)" pip install scipy
import
https://blog.csdn.net/weixin_38256474/article/details/81228492 https://www.devdungeon.com/content/python-import-syspath-and-pythonpath-tutorial
概念
- 模块 module,.py、.pyo、.pyc、.pyd、.so、.dll
- 包 package, 包含有 module 的目录,通过 init.py 标示
- init.py 包的描述文件
从 sys.path 和 PYTHONPATH 查找模块或包
conda
Package, dependency and environment management for any language
相当于 pip + virtualenv
合理是预编译好的包,不同的 cpu 架构可能有支持上的问题
Miniconda
Anaconda
-
预装了 1500 个科学计算包,占 3GB 空间
mamba
conda 加强版 https://github.com/mamba-org/mamba
- 多线程下载
- 更快的依赖解析
- c++ 实现
conda-forge
社区维护的 conda channel,相当于社区版 anaconda?
Resources
https://realpython.com/effective-python-environment/#package-management
Basic
Scope
- 本地作用域,function 或 lambda 表达式
- 外部作用域(Enclosing scope),比如闭包,或上层作用域
- 全局作用域(Global),在程序或模块的最外层定义的变量
- 内置作用域(Build-in),比如关键字,内置函数
python 查找变量也是按照这个顺序。值得注意的是 python 没有块作用域,即除了 function
或 lambda
之外的代码块是没有本地作用域,比如 while
try-except
,特别是 for
语句中声明的变量,仍然在本地作用域。
Python 作用域通过 dictionaries
实现的,这些 dictionaries
通常也叫 namespaces。
module 的变量名存放与 __dict__
,比如: sys.__dict__
,如果当前程序的话:globals()
、dir()
在非全局作用域,为全局变量赋值是需要 global
关键字,访问全局变量则不用。
同样的,嵌套作用域要修改,外部作用域的变量,需要用 nonlocal
,这里可以发现使用来 nonlocal
关键字表示要为闭包保存外部环境的引用。
几个特殊情况
- python 没有块作用域,列表推导式(Comprehension)却是有的。
- except 表达式中声明的变量
- 类,拥有自己的本地作用域
__dict__
- 实例,也拥有自己的
__dict__
,所以在类的定义中,要访问实例的作用域需要self
- 另外,类的作用域并不是方法的外部作用域,类的方法需要通过类的引用才能访问到类的作用域。
- 通过实例变量查找变量,会先从实例本地作用域,到类本地作用域,如果找不到会抛出
AttributeError
.
列表推导式(Comprehension)
通过表达式生成新的列表:
new_list = [expression for member in iterable]
expression
可以访问 member
,还支持 filter
:
new_list = [expression for member in iterable if conditional]
集合(元素具有唯一性)推导式:
new_set = {expression for member in iterable}
字典推导式:
squares = {i: i * i for i in range(10)}
生成器(reduce):
sum(i * i for i in range(1000000000))
模块与包
三种定义 python 模块的方式:
- python 声明,如名为 mod 的python 模块,即文件名为
mod.py
的 python 脚本 - c 实现,运行时动态加载
- 解析器的内置模块,如
itertools
模块搜索路径
- 当前路径
PYTHONPATH
环境变量- 安装时设置的特殊位置,如:
site-package
包
一个文件夹以树状结构(文件系统)组织模块的集合:
import pkg.mod1, pkg.mod2
import pkg
不会自动把 pkg 内的模块导入。而是执行 __init__.py
from pkg import *
能把 __init__.py
中声明的模块导入:
__all__ = [
'mod1',
'mod2',
'mod3',
'mod4'
]
Thread
由于与GIL
的交互实际上限制了一次运行一个Python线程。还有一个 multiprocessing
使用子进程并发的包代替。
基本的启动线程的形式:
x = threading.Thread(target=thread_function, args=(1,))
x.start()
线程池:
import concurrent.futures
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
executor.map(thread_function, range(3))
加锁:
lock = threading.Lock()
with lock:
....
....
- 信号:
event = threading.Event()
- 信号量:
threading.Semaphore
- 定时器:
threading.Timer
GIL
Global Interpreter Lock
python 用引用计数来做 GC,GIL 就是来保证引用计数过程中的线程安全。