news 2026/10/4 3:10:46

Python 2和3多版本共存:pyenv+venv完整实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python 2和3多版本共存:pyenv+venv完整实战指南

各位同行,说起Python多版本共存这件事,我估计不少人都经历过那种“血压飙升”的瞬间。特别是前几年还在维护Python 2遗留项目的人,一边是线上跑得好好的Django老系统,只能依赖2.7环境,一边是新项目需要Python 3.8以上的特性,结果同一台机器上两个版本互相打架。最典型的就是你在终端敲pip install,明明感觉装上了,一import却提示找不到模块,折腾半天发现 pip 指向的是另一个版本的Python。今天这篇文章,我就把Python 2和Python 3在同一系统下多版本共存的完整方案讲明白,从原理到底层机制,从工具选型到实战步骤,再到各种归档级的踩坑记录,全部摊开来讲。

这篇内容适合谁看?只要你需要维护老项目、又要写新代码,或者需要在同一台开发机、同一台服务器上跑多个Python版本,那这篇文章就是给你准备的。我会重点讲Linux下的方案,因为生产环境里Linux最为常见,同时也会顺带提一下macOS和Windows的处理思路。读完你不仅能装好环境,更重要的是能理解这里面每一步到底在做什么,以后遇到问题排查起来才有方向感。

1. 整体设计思路:先搞清楚“共存”到底在解决什么问题

1.1 核心痛点:Python版本隔离为什么这么难

Python 2和Python 3不兼容,这是历史遗留的现实。但很多人在处理共存问题时,思路一开始就错了,跑去改系统默认的python软链接,或者直接把某个版本卸载重装,结果越弄越乱。要理清这个问题,得先明白Python安装到系统里之后,到底有哪几层东西在起作用。

第一层是解释器本体,也就是python2和python3这两个可执行文件,它们各自指向不同版本的二进制。第二层是标准库和第三方包,Python 2和Python 3的site-packages目录是分开的,如果两个版本共用同一个第三方库目录,那绝对会出乱子。第三层是命令行工具的入口脚本,比如pip、pytest、supervisor这些工具,它们安装时会在bin目录下生成可执行文件,文件头部用shebang指定了用哪个解释器运行。这三层只要有一层指向混乱,就会出现“装了包找不到、命令执行报错、版本对不上号”的问题。

所以共存的本质不是简单地“装两个Python”,而是要建立一套清晰的隔离和切换机制,让操作系统、终端、项目都能准确找到自己需要的那一套环境。

1.2 方案选型:为什么推荐“pyenv + venv”组合

市面上处理多版本共存的工具有不少,我拿它们做过对比,各有优劣。

第一种是直接用系统的包管理器,比如apt安装python2.7和python3.8,然后通过update-alternatives切换。这个方案的优点是安装简单,缺点是版本号被系统锁死,想装一个“非官方”的Python小版本就麻烦了,而且系统级包管理器升级时可能覆盖配置,风险不小。另外update-alternatives只是切换命令行入口,第三方库和工具脚本依然可能混乱。

第二种是Anaconda/Miniconda。conda确实是多版本管理的利器,尤其是数据科学领域,环境隔离做得非常干净,Windows、macOS、Linux通吃。但它也有自己的问题:conda创建的环境默认带了一套完整的科学计算包,体积大、依赖重,和系统Python的交互逻辑也比较自成一体。对于只想单纯管理Python版本、不想被conda生态绑定的场景来说,有点杀鸡用牛刀。

第三种是我最常用的方案:pyenv 管理多个Python解释器版本,venv 管理每个项目独立的第三方包环境。这两个工具各管一层,互不干扰。pyenv只负责搞定解释器本身,让不同的Python版本可以同时存在、快速切换;venv则基于某个特定的Python解释器创建出独立的虚拟环境,每个环境有自己独立的site-packages目录,互相隔离。这样组合起来,从上到下每一层都清清楚楚。

为什么最终选择pyenv?因为它在Linux/macOS上表现最稳定,工作原理也很透明:通过修改PATH环境变量和一段shell脚本钩子机制,把python这个命令“劫持”到指定版本的可执行文件上。我们不需要动系统自带的Python,安全性很高。

1.3 版本兼容性矩阵:Python 2和Python 3的生态差异

既然要共存,就不得不面对两者的生态差异。Python 2.7是Python 2系列的最后一个版本,官方在2020年1月1日停止维护,虽然不再更新,但大量历史项目仍在运行。Python 3则持续推进,3.6到3.12每个版本都有新特性,但不少第三方库对版本也有要求。

规划共存方案时,我一般会建一张兼容性清单,列出项目中使用的第三方库与Python版本的对应关系。比如MySQLdb只支持Python 2,换到Python 3就得用PyMySQL或者mysqlclient;Twisted在Python 3.6以上才有稳定支持;而新版Django早就抛弃了Python 2。只有把依赖库的版本要求摸清楚,才能确定需要装哪几个Python解释器版本。

2. 核心细节解析:pyenv的安装、编译与切换机制

2.1 环境准备:依赖库一个都不能少

先声明一下,下面的操作基于Ubuntu 20.04 LTS,其他Linux发行版的包名略有差异,但思路一样。

pyenv安装Python时其实是从源码编译的,不是下载现成的二进制包,所以系统里必须装齐编译工具链和依赖库。我最初偷懒少装了一个libssl-dev,结果Python编译出来之后pip用不了HTTPS,装啥都报SSL错误,折腾到怀疑人生。

执行以下命令安装编译依赖:

sudo apt update sudo apt install -y make build-essential libssl-dev zlib1g-dev \ libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm \ libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev

这里每个依赖都有它存在的理由:zlib1g-dev是Python的zlib压缩模块需要的,缺了它ensurepip可能直接失败;libreadline-dev影响交互式环境的上下键历史功能;libsqlite3-dev则关系到sqlite3标准库能否正常导入。如果你打算用Python 3.7以上的版本,libffi-dev尤其重要,否则ctypes模块会出问题。

macOS用户需要先装Xcode Command Line Tools,然后执行brew install openssl readline sqlite3 xz zlib tcl-tk。Windows用户呢,我的建议是直接用Python官网的安装包装多个版本,然后通过py启动器来切换,pyenv在Windows原生环境下的体验确实一般。

2.2 pyenv安装与配置:把PATH机制握在手里

依赖安装好之后,用git把pyenv克隆到用户目录下:

git clone https://github.com/pyenv/pyenv.git ~/.pyenv

然后在~/.bashrc最末尾追加这几行配置:

export PYENV_ROOT="$HOME/.pyenv" export PATH="$PYENV_ROOT/bin:$PATH" eval "$(pyenv init -)"

执行source ~/.bashrc让配置生效,然后输入pyenv --version确认安装成功。这里要重点说一下eval "$(pyenv init -)"的作用:它会在shell里注册一个名为pyenv的shell函数,这个函数能拦截你敲的python、pip命令,根据pyenv当前的配置动态决定把它们解析到哪个真实的解释器。这就是pyenv切换版本的核心机制,不是简单替换软链接,而是在命令执行前动态重定向。

如果你用的是zsh,把.bashrc换成.zshrc即可。修改完配置之后建议新开一个终端窗口,避免当前shell环境没加载最新PATH配置。

2.3 安装Python 2.7与Python 3.x:版本选择与编译参数

接下来就是真正安装Python解释器了。先列出pyenv里可用的所有版本号:

pyenv install --list

这个列表非常长,包含了CPython、Anaconda、PyPy等各种发行版。我们只需要CPython,并且注意区分版本号。

以我的项目环境为例,老项目需要Python 2.7.18,新项目需要Python 3.8.18和Python 3.11.9,分别执行安装命令:

pyenv install 2.7.18 pyenv install 3.8.18 pyenv install 3.11.9

第一次编译通常需要几分钟,取决于机器性能。安装过程中会输出编译日志,如果出现错误,在日志末尾能看到具体缺少哪个依赖。有一种情况值得注意:如果机器内存比较小,Python 3.8以上的版本编译时可能会因为并行编译导致内存不足,可以在编译前设置MAKEFLAGS="-j1"来单线程编译,代价是更长的编译时间。

另外,如果公司内网环境无法访问GitHub和Python官方源码站,pyenv install会直接失败。解决方案是手动下载源码包放到~/.pyenv/cache目录下,pyenv发现缓存里有对应版本的源码包,编译时就会直接用本地的,不再联网下载。这个离线安装的细节在生产环境里极其好用。

2.4 版本切换的三种姿势:global、local、shell

pyenv装好多个版本后,切换方式有三种,对应不同粒度的使用场景。

全局切换,pyenv global 3.11.9,意思是整个用户环境下默认使用Python 3.11.9。这个设置会写入~/.pyenv/version文件,打开任何终端都生效。

目录级切换,pyenv local 2.7.18,这条命令会在当前目录生成一个.python-version文件,内容就是2.7.18。pyenv会自动识别当前目录下有没有这个文件,有的话就切换成对应版本。这个特性非常实用,进入老项目目录自动切到Python 2.7,进入新项目目录自动切到Python 3.11,团队协作时把这个文件提交到仓库,大家环境就统一了。

会话级切换,pyenv shell 3.8.18,只在当前终端会话内临时切换,关闭终端就失效,适合临时跑某个脚本的场景。

用pyenv versions命令可以看到当前用户下所有已安装的版本,以及当前生效的版本,带星号的那个就是当前正在使用的。我个人习惯用pyenv version查看当前版本,命令更短,输出也更直接。

2.5 实测验证:检查解释器路径与pip指向

安装并切换之后,一定要做一次完整的自检。我每次配完新环境都会跑一遍下面的命令:

which python python --version which pip pip --version python -c "import sys; print(sys.executable)"

which python拿到的是pyenv shim的路径,也就是~/.pyenv/shims/python,这是pyenv生成的一个脚本转发层,不是真正的解释器。执行时它会根据.python-version文件的设置,把调用转发给真正的解释器。python --version则能看到当前实际生效的Python版本。

关键看pip --version的输出,它会明确告诉你当前pip归属于哪个Python解释器、装在哪个目录下面。正常情况下输出类似:

pip 22.0.4 from /home/user/.pyenv/versions/3.11.9/lib/python3.11/site-packages/pip (python 3.11)

如果你发现pip指向的版本和python指向的不一致,那就要检查是不是同时装了系统自带的pip,导致PATH环境变量里系统路径排在pyenv路径前面。这种情况虽然不常见,但一旦出现,用echo $PATH看一下顺序就能定位。

3. 实操过程:从零搭建一套完整的双版本环境

3.1 创建项目虚拟环境:不同项目不同沙盒

解释器层面的共存解决之后,还剩一个同样关键的问题:第三方包怎么隔离。举个真实例子,项目A用Python 2.7跑Django 1.11,依赖的django-redis版本是4.x;项目B用Python 3.11跑Django 4.2,依赖的django-redis是5.x。如果两个项目共用一套site-packages,那基本就是灾难,装一个包把另一个项目的依赖覆盖了。

所以每个项目必须建独立虚拟环境。pyenv提供了一个很好用的插件叫pyenv-virtualenv,可以在pyenv的版本体系里创建和管理虚拟环境。先安装插件:

git clone https://github.com/pyenv/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv

然后执行:

pyenv virtualenv 2.7.18 my-legacy-project pyenv virtualenv 3.11.9 my-new-project

创建好之后,pyenv versions里就会多出两个带my-legacy-project和my-new-project后缀的环境名。在对应项目目录里执行:

pyenv local my-legacy-project

这样进入目录后,自动激活对应的虚拟环境,python和pip都指向虚拟环境内的解释器和包目录。

如果你不想装插件,Python 3.3以上版本自带的venv模块也能干这事:

python3.11 -m venv /path/to/venv source /path/to/venv/bin/activate

区别在于venv创建的虚拟环境和pyenv之间没有联动关系,激活方式靠source命令直接修改PATH环境变量,项目管理上稍微麻烦一点,但胜在干净无插件依赖。两种方式看个人喜好。

3.2 pip源配置与依赖安装:30秒搞定包管理

虚拟环境激活之后,安装依赖跟平时一样用pip即可。国内网络环境访问默认的PyPI源速度很慢,我一般会先配置一个国内镜像源。方法是在用户目录下编辑~/.pip/pip.conf(Linux)或%APPDATA%\pip\pip.ini(Windows):

[global] index-url = https://pypi.tuna.tsinghua.edu.cn/simple trusted-host = pypi.tuna.tsinghua.edu.cn

Python 2.7和Python 3的pip都读同一份配置文件,所以只改一次就够了。注意trusted-host是必须的,否则pip会拒绝连接非HTTPS源。

安装依赖时有个小经验:如果项目里有requirements.txt,先不要一上来就pip install -r requirements.txt,先装pip自身和环境核心依赖,把pip升级到最新版,尤其是Python 2.7环境,老版本的pip连manylinux2014格式的wheel包都识别不了,安装会报Invalid wheel filename错误。

3.3 一个完整案例:同一服务器部署两个Python项目

光讲理论不落地是耍流氓,我拿一个实际场景来演示:同一台服务器上同时部署一个Python 2.7的旧后台和一个Python 3.11的新服务。

服务器上先确保pyenv装好,然后执行两次pyenv install,把两个解释器都装好。接着为两个项目分别创建虚拟环境并安装依赖:

mkdir -p /srv/projects/legacy cd /srv/projects/legacy pyenv local legacy-env pip install -r requirements.txt mkdir -p /srv/projects/newapi cd /srv/projects/newapi pyenv local newapi-env pip install -r requirements.txt

两个项目的目录下都会生成.python-version文件,分别写着legacy-env和newapi-env。使用systemd管理服务时,ExecStart里直接写全路径:

ExecStart=/root/.pyenv/shims/python /srv/projects/legacy/manage.py runserver 0.0.0.0:8001 ExecStart=/root/.pyenv/shims/python /srv/projects/newapi/app.py 0.0.0.0:8002

这里直接用shims路径,好处是systemd不需要读取shell配置,也能通过pyenv shim转发到正确的解释器。或者更稳妥的做法是使用虚拟环境内的python绝对路径,比如/root/.pyenv/versions/legacy-env/bin/python。我实际部署时会用后一种方式,因为shim依赖登录shell环境变量,systemd环境下容易出幺蛾子。

这套方案上线后运行了两年多,两个项目互不干扰,升级依赖也互不影响,非常稳。

3.4 IDE配置:VSCode和PyCharm里的多版本切换

命令行搞定了,IDE也得跟上。VSCode里多版本切换的核心是选择正确的解释器路径。安装了Python插件后,按Ctrl+Shift+P打开命令面板,输入Python: Select Interpreter,VSCode会自动扫描pyenv的虚拟环境列表,直接选中对应环境即可。

如果需要项目级固定配置,在项目根目录创建.vscode/settings.json:

{ "python.defaultInterpreterPath": "/root/.pyenv/versions/legacy-env/bin/python" }

PyCharm的操作类似,进入Settings -> Project -> Python Interpreter,点击齿轮选择Add,然后选择Existing Environment并填入pyenv虚拟环境的解释器路径,最后确认。IDE的自动检测虽然方便,但有时候会扫描出很多无关的解释器,选择时留意路径是否在~/.pyenv/versions/下面即可。

4. 常见问题与排查技巧:多版本共存的典型故障记录

4.1 编译安装阶段的高频报错

报错:ERROR: The Python ssl extension was not compiled. Missing the OpenSSL lib?

这个报错几乎90%的pyenv编译失败都源于它。原因就是系统缺少OpenSSL开发头文件,按前面提到的libssl-dev安装一下,然后重新装Python版本。有个细节要提醒,Ubuntu 22.04以上系统里OpenSSL可能升级到3.0,老版本Python编译时会出现兼容问题,需要额外安装libssl1.1,或者指定编译参数让Python链接到旧版本库。

报错:ModuleNotFoundError: No module named '_bz2'

同样典型的依赖缺失症状,说明编译时没找到libbz2-dev开发库。安装后重新编译即可。这类问题因为依赖项太多,一次装齐的性价比远比逐个报错逐个装要高。

报错:zipimport.ZipImportError: can't decompress data; zlib not available

少了zlib1g-dev库,按前面的依赖列表装齐就解决了。这三个报错是入门必踩,我把它放在最前面是希望你别在这些地方浪费时间。

4.2 pip与包管理相关的经典问题

问题:装到了“别的Python”里

pip install requests之后,写脚本import requests却报ModuleNotFoundError。这个我猜所有人都遇到过。排查思路很简单,先看当前pip --version指向哪个解释器,再对比当前python --version指向哪个解释器,如果不一致,就用python -m pip install requests来确保装到当前python对应的环境里。

问题:Python 2.7环境里pip升级后不可用

Python 2.7自带的pip版本很老,直接pip install --upgrade pip可能升到最新版,但最新版pip已经不支持Python 2了,升级完了会直接报语法错误无法运行。正确做法是升级到支持Python 2的最后一个版本:pip install --upgrade 'pip<21'。这个问题很隐蔽,我当初帮人排查了好久才定位到是pip版本太新导致解释器不兼容。

问题:No matching distribution found for requests

这个一般是pip源里没有当前平台对应的安装包,或者pip版本太老认不出新格式的wheel包。先升级pip,再确认源配置正确。Python 2.7环境特别容易遇到,因为很多新包已经不再发布支持Python 2的版本了,这种情况只能从requirements.txt里锁定旧版本号。

4.3 node-gyp、工具链与系统级兼容问题

问题:npm安装node-sass等原生模块时报python2 not found

很多Node.js的原生模块在编译时需要Python 2作为构建脚本的解释器,比如node-sass、node-gyp。系统里如果没有python2命令,构建就会失败。解决办法是在~/.npmrc里指定:

python=/root/.pyenv/versions/2.7.18/bin/python

或者安装时直接传参:npm install --python=/root/.pyenv/versions/2.7.18/bin/python。这个坑在维护老前端项目时非常常见,配置好之后一劳永逸。

问题:/usr/bin/env: 'python': No such file or directory

一些老脚本的shebang写的是#!/usr/bin/env python,系统里没有python这个命令时就会报这个错。我用update-alternatives或者直接建软链接解决:sudo ln -s /root/.pyenv/versions/2.7.18/bin/python /usr/local/bin/python。但这里要非常小心:不要覆盖系统自带的python3命令,也不要在系统级傻傻地把python指向2.7然后期望它同时兼容3.x,这样只会造成更大的混乱。

问题:shell初始化时pyenv报错pyenv: command not found

这种基本是写环境变量的位置不对,或者当前shell是zsh但你改的却是.bashrc。用echo $SHELL先确认当前shell类型,zsh就用~/.zshrc,bash就用~/.bashrc,改完记得source或者新开会话。

4.4 排查问题的方法论:三步定位法

不管遇到什么诡异的问题,我排查的思路都是三句话:先看版本再看路径,最后才怀疑依赖。

第一步看python --version和pip --version是否一致;第二步看which python的实际路径对不对,是不是指向预期版本;第三步看关键依赖是否装好,用python -c "import ssl; print(ssl.OPENSSL_VERSION)"验证。版本对了、路径对了,90%的问题都能定位出来,剩下10%才是依赖和编译层面的问题。

5. 进阶扩展:离线安装、环境迁移与超高效率技巧

5.1 离线环境安装多版本Python的完整链路

不少生产服务器在内网隔离区,没法直接访问外网。这种环境下用pyenv安装Python的思路要变一下。

首先在一台能联网的机器上,先创建~/.pyenv/cache目录,然后用pyenv install把需要的版本装一遍,装好之后到~/.pyenv/versions目录把对应的版本目录打包。也可以只下载源码包,放到离线机器的~/.pyenv/cache目录下,再执行pyenv install,pyenv检测到缓存存在就不会再联网。

第三方依赖包的离线安装可以参考这个思路:先用联网机器创建虚拟环境,再pip download -r requirements.txt -d /tmp/packages把包全部下下来,拷到离线机器后pip install -r requirements.txt --no-index --find-links=/tmp/packages,这样pip就不走网络,只从本地目录找包。

顺便说一句,Python 2.7的源码包在官方仓库已经处于归档状态,某些老版本可能找不到下载地址,如果pyenv install报了下载失败,去~/.pyenv/cache里手动放一份源码包是最省心的方案。

5.2 环境迁移与团队协作的最佳实践

团队里多人开发,最怕“在我机器上是好的”这种问题。用pyenv + .python-version可以有效缓解。项目里提交.python-version文件,别人clone下来进入目录就会自动切换对应的Python版本或虚拟环境,然后装依赖即可,基本没有版本不一致的问题。

环境迁移时,项目依赖清单一定要用pip freeze或pipreqs生成,避免手工维护由于漏装导致环境不完整。pip freeze会把当前环境所有包导出来,包括很多间接依赖,好处是环境还原度高,坏处是PyPI上某几个老包可能已经被下架,安装时会报404。这时候就需要手工从源码包安装,或者从已有环境里打包site-packages目录整个移植,这个办法虽说土了点,但效果其实很好。

5.3 提高效率:让命令少敲一半的小技巧

日常开发中,来回切目录、频繁输pyenv local其实也够烦的。我在~/.bashrc里配了几个别名和函数:

alias py2="pyenv local legacy-env" alias py3="pyenv local newapi-env" function pyenv-activate() { local venv_name="$1" pyenv activate "$venv_name" }

配合pyenv-virtualenv的自动激活功能,每次进入项目目录,终端提示符前面会出现当前虚拟环境名,一眼就知道自己处于哪个环境,不会再出现“我以为我在项目A里,结果装包装到了项目B”的尴尬。

6. 写在最后的几句大实话

Python 2和Python 3多版本共存这件事,本质上没有多高深的技术含量,它就是一套“分层隔离”思想的实践:解释器归pyenv管,第三方包归venv管,项目环境归.python-version管,每一层只做一件事,而且只做自己该做的那件事。很多人把它搞复杂,是因为总想用一把锤子解决所有问题,要么只切软链接、要么只用虚拟环境,结果版本乱了、包也乱了,最后只能重装系统。

我个人在实际操作中还有一条自己的原则:永远不要动系统自带的Python。系统Python是给apt和系统工具用的,你强行换掉它的版本,轻则某些系统命令出问题,重则整个系统桌面或服务都可能崩掉。所有业务代码、工具、虚拟环境,一律放到pyenv管理的目录下,这样整个环境的可控性和可回溯性都高很多。

最后再分享一个小技巧:如果你维护着多个老项目,建议把每个人项目的.python-version文件内容记下来,顺便用pyenv install --list里的版本号标注一下当前项目可用的版本。以后遇到同事问你“这个项目是用哪个版本跑的”,你就不用翻聊天记录了,一个命令cat .python-version就搞定。环境统一了,沟通成本直线下降,这才是多版本共存方案真正的价值所在。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/4 3:09:28

一个 46% 对 19% 的调查,把程序员这两年纠结的事全说透了

上个月在群里看到一份 2026 年的开发者调查&#xff0c;问的是"哪款 AI 编程工具你最喜欢"&#xff0c;结果一出来我愣了一下&#xff1a;Claude Code 拿了 46%&#xff0c;Cursor 只有 19%&#xff0c;GitHub Copilot 更惨。这个落差比我预想的要大太多。要知道两年…

作者头像 李华
网站建设 2026/10/4 3:07:18

Beamer主题与配色完全指南:从入门到自定义模板

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/4 3:03:05

一套代码跑通iOS、安卓、鸿蒙:跨端技术栈选型与落地实践

跨端技术栈这事&#xff0c;我被问过太多次了&#xff0c;尤其是“iOS、安卓、鸿蒙三端同时要”这个需求&#xff0c;基本是这两年移动端团队里出现频率最高的一句话。原因也不难理解&#xff0c;以前做App&#xff0c;打包两个端就已经够折腾&#xff0c;现在鸿蒙加入进来&…

作者头像 李华
网站建设 2026/10/4 3:02:15

Silvaco光电仿真实战:响应度与暗电流的物理建模与校准

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/4 2:57:45

长沙曾食坊小吃培训的烤鱼与纸包鱼:炭火与锡纸两条线

本篇要点&#xff1a; 1. 炭火直烤与锡纸包烤区别&#xff1b;2. 腌制锁水与浇汁&#xff1b;3. 上桌后续热。烤鱼和纸包鱼常被混为一谈&#xff0c;实则两条工艺线。本文补的是炭火与锡纸在烤制上的那一层&#xff1a;从腌制锁水、浇汁时机&#xff0c;到上桌后怎么续热&#…

作者头像 李华
网站建设 2026/10/4 2:57:06

手机里舍不得删的5款安卓神器

做自媒体、搞副业、一个人顶一个公司&#xff0c;常怕这两件事&#xff1a;一是手机装一堆app&#xff0c;要么满屏广告、要么所需功能要会员权限&#xff1b;二是一点点工作得在好几个软件之间来回倒腾&#xff0c;时间全耗在找东西、转格式、解压、点广告这些破事上。本期然百…

作者头像 李华