<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>虚拟环境管理工具 &#8211; 李辉 / Grey Li</title>
	<atom:link href="https://greyli.com/tag/%E8%99%9A%E6%8B%9F%E7%8E%AF%E5%A2%83%E7%AE%A1%E7%90%86%E5%B7%A5%E5%85%B7/feed/" rel="self" type="application/rss+xml" />
	<link>https://greyli.com</link>
	<description>一个编程和写作爱好者的在线记事本</description>
	<lastBuildDate>Thu, 06 Nov 2025 11:36:11 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.9.26</generator>

<image>
	<url>https://greyli.com/wp-content/uploads/2025/03/avatar-500-compressed-144x144.jpg</url>
	<title>虚拟环境管理工具 &#8211; 李辉 / Grey Li</title>
	<link>https://greyli.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>要不我们还是用回 virtualenv/venv 和 pip 吧</title>
		<link>https://greyli.com/back-to-virtualenv-venv-and-pip/</link>
		<comments>https://greyli.com/back-to-virtualenv-venv-and-pip/#comments</comments>
		<pubDate>Sat, 07 Sep 2019 06:11:35 +0000</pubDate>
		<dc:creator><![CDATA[李辉]]></dc:creator>
				<category><![CDATA[计算机与编程]]></category>
		<category><![CDATA[pip]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[venv]]></category>
		<category><![CDATA[virtualenv]]></category>
		<category><![CDATA[依赖管理]]></category>
		<category><![CDATA[虚拟环境管理工具]]></category>

		<guid isPermaLink="false">http://greyli.com/?p=2551</guid>
		<description><![CDATA[这篇文章没什么新东西，只是介绍古老又靠谱的 Python 虚拟环境和依赖管理方式：virtualenv/ven [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>这篇文章没什么新东西，只是介绍古老又靠谱的 Python 虚拟环境和依赖管理方式：virtualenv/venv+pip。一来方便被我在《Flask 入门教程》和《Flask Web 开发实战》带入 <a href="http://greyli.com/do-not-use-pipenv/">Pipenv 坑</a>的初学者了解基础工具的用法，二来方便其他 Python 初学者参考，自己顺便做个总结。<span data-offset-key="2c438-0-0">如果你想了解更多详细内容，Python 官方教程</span><a class="Link ztext-link" href="https://docs.python.org/3/tutorial/venv.html" target="_blank" rel="noopener" data-offset-key="2c438-1-0" data-editable="true"><span data-offset-key="2c438-1-0">这一章</span></a><span data-offset-key="2c438-2-0">写的更好，可以替代这篇文章。</span></p>
<p>既然大部分试图简化 Python 虚拟环境和依赖管理工作流程的新工具都不够稳定，继续使用 virtualenv/venv 和 pip 这样的底层工具也是一个不错的选择，而且大多数人也是这么做的。它们虽然用起来有一点麻烦，但至少更可靠。</p>
<h2>基本概念</h2>
<p>下面是一些基本概念：</p>
<ul>
<li><a href="https://www.pypa.io/en/latest/">PyPA</a>：指 Python Packaging Authority，一个维护 Python 打包相关项目的小组，相关项目具体见 <a href="https://github.com/pypa">https://github.com/pypa</a>。</li>
<li><a href="https://pip.pypa.io/en/stable/">pip</a>：Python 包安装器 。</li>
<li><a href="https://virtualenv.pypa.io/en/stable/">virtualenv</a>：Python 虚拟环境管理工具。</li>
<li><a href="https://docs.python.org/3/library/venv.html">venv</a>：Python 标准库内置的虚拟环境管理工具，Python 3.3 加入，Python 3.5 开始作为管理虚拟环境的推荐工具，用法类似 virtualenv。如果你使用 Python 3，推荐使用 venv 来替代 virtualenv。</li>
</ul>
<h2>使用 virtualenv/venv 管理虚拟环境</h2>
<h3>venv 模块</h3>
<p>如果你使用 Python 3（具体说是 Python 3.3 及以上版本），推荐使用标准库内置的 <a href="https://docs.python.org/3/library/venv.html">venv 模块</a>替代 virtualenv，两者的使用方式基本相同，唯一不同的是创建虚拟环境的方式。</p>
<p>如果你使用 Python 2，那就只能选择 virtualenv，你需要额外安装它。我先假设你已经安装了 pip，因为在 Python 2 &gt;=2.7.9 或 Python 3 &gt;=3.4 这些版本的 Python 会一并安装 pip，其他版本可以参考文档的<a href="https://pip.pypa.io/en/stable/installing/">安装部分</a>。在 Windows 下使用下面的命令安装 virtualenv：</p>
<pre class="">$ pip install virtualenv</pre>
<p>其他操作系统可以使用下面的命令安装：</p>
<pre class="">$ sudo pip install virtualenv</pre>
<p>尽管<a href="https://pages.charlesreid1.com/dont-sudo-pip/">不推荐使用 sudo pip</a> 的方式安装 Python 包，但这仍然是最简单和统一的方式。更安全的方式是使用系统包管理器来安装，或是使用 pip &#8211;user 方式安装。</p>
<h3>创建虚拟环境</h3>
<p>假设我们的项目名叫 snow，创建对应的文件夹然后切换到根目录：</p>
<pre class="">$ mkdir snow
$ cd snow</pre>
<p>如果使用 venv，那么使用下面的命令创建虚拟环境，其中 snow-venv 是虚拟环境的名字，也作为创建的虚拟环境文件夹名称，你可以自由修改（通常会使用 venv 或 env 作为虚拟环境名）：</p>
<pre class="">$ python -m venv snow-venv</pre>
<p>如果使用 virtualenv，则使用下面的命令：</p>
<pre class="">$ virtualenv snow-venv</pre>
<p>这会在当前目录创建名为 snow-venv 的虚拟环境文件夹，你需要把这个文件夹名称加入 .gitignore 文件以便让 Git 忽略。</p>
<h3>激活虚拟环境</h3>
<p>通过执行对应的激活脚本来激活虚拟环境，不同操作系统的激活命令（激活脚本及路径）有一点不同。Windows（CMD.exe）使用下面的命令激活：</p>
<pre class="">$ snow-venv\scripts\activate</pre>
<p>Linux 和 macOS（bash/zsh）使用下面的命令：</p>
<pre class="">$ source snow-venv/bin/activate</pre>
<p>或：</p>
<pre class="">$ . snow-venv/bin/activate</pre>
<p>类似的，其他终端程序可以执行对应的激活脚本来激活虚拟环境。</p>
<p>激活虚拟环境以后，命令行提示符前会显示当前虚拟环境的名字：</p>
<pre class="">(snow-venv) $</pre>
<p>使用 deactivate 命令可以退出虚拟环境。</p>
<h2>使用 pip 管理依赖</h2>
<p>简单列一下基本用法，虽然大部分人都很熟悉了……以 Flask 为例，首先是安装依赖：</p>
<pre class="">(snow-venv) $ pip install flask</pre>
<p>更新依赖：</p>
<pre class="">(snow-venv) $ pip install --upgrade flask</pre>
<p>或是：</p>
<pre class="">(snow-venv) $ pip install -U flask</pre>
<p>卸载依赖：</p>
<pre class="">(snow-venv) $ pip uninstall flask</pre>
<p>除此之外，还有 pip show flask 命令可以查看某个依赖的详细信息，pip list 列出所有依赖。</p>
<p>下面的命令可以手动生成依赖列表：</p>
<pre class="">(snow-venv) $ pip freeze &gt; requirements.txt</pre>
<p>如果你需要手动开发依赖和生产依赖，可以手动把开发相关的依赖放到单独的文件，比如 requirements-dev.txt。</p>
<p>当你需要在新的机器创建程序运行环境时，（创建虚拟环境后）只需要使用下面的命令从依赖文件安装所有依赖：</p>
<pre class="">(snow-venv) $ pip install -r requirements.txt</pre>
<p>如果安装包的时候速度太慢，可以考虑设置 PyPI 国内镜像，具体参考<a href="http://greyli.com/set-custom-pypi-mirror-url-for-pip-pipenv-poetry-and-flit/">这篇文章</a>。</p>
<h2>从其他工具迁移回来</h2>
<p>如果你想从 Pipenv 迁移回来，方法很简单，只需要生成一个 requirements.txt 文件即可。使用下面的命令生成一般依赖列表：</p>
<pre class="">$ pipenv lock -r</pre>
<p>使用下面的命令输出开发依赖列表：</p>
<pre class="">$ pipenv lock -r --dev</pre>
<p>然后手动把两个命令的输出保存为 requirements.txt 和 requirements-dev.txt。</p>
<p><span data-offset-key="571ch-0-0">从 Poetry、Conda 等其他工具迁移回来可以使用 </span><a class="Link ztext-link" href="https://github.com/bndr/pipreqs" target="_blank" rel="noopener" data-offset-key="571ch-1-0" data-editable="true"><span data-offset-key="571ch-1-0">pipreqs</span></a><span data-offset-key="571ch-2-0"> 来生成 requirements.txt，它会基于项目代码的导入语句来生成依赖列表。</span></p>
<p>在下一篇文章，我会介绍一些辅助工具来搭配 virtualenv/venv+pip 使用，让虚拟环境和依赖管理更方便，比如 virtualenvwrapper、pip-tools 等。</p>
<p>（4）</p>
]]></content:encoded>
			<wfw:commentRss>https://greyli.com/back-to-virtualenv-venv-and-pip/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>不要用 Pipenv</title>
		<link>https://greyli.com/do-not-use-pipenv/</link>
		<comments>https://greyli.com/do-not-use-pipenv/#comments</comments>
		<pubDate>Sat, 31 Aug 2019 07:16:30 +0000</pubDate>
		<dc:creator><![CDATA[李辉]]></dc:creator>
				<category><![CDATA[计算机与编程]]></category>
		<category><![CDATA[Pipenv]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[虚拟环境管理工具]]></category>

		<guid isPermaLink="false">http://greyli.com/?p=2544</guid>
		<description><![CDATA[注意：本文写于 2019 年 8 月，其中描述的内容在新版本的 Pipenv 中或已得到修复或改进，请谨慎参考 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>注意：本文写于 2019 年 8 月，其中描述的内容在新版本的 Pipenv 中或已得到修复或改进，请谨慎参考。</p>
<p>如果你是《Flask Web 开发实战》的读者，请访问<a href="http://greyli.com/flask-web-book-pipenv-problem-solved/">《Flask Web 开发实战》虚拟环境/依赖/Pipenv 等问题解决方法</a>。</p>
<hr />
<p>Pipenv 让我用的很痛苦，有一种被欺骗的感觉，而且很后悔在《<a href="http://greyli.com/flask-web-development/">Flask Web 开发实战</a>》里采用它。</p>
<p>大部分情况下，它很好用，但却存在太多问题，有一些问题让人简直没法接受。我知道有人会说「这是开源程序，有 bug 就自己去修」、「爱用不用，没人强迫你」，但问题是，一个进行大肆推广，甚至借 PyPA 做背书来宣传（经常让人误以为是 Python 官方推荐）的工具却连基本的使用流程都没做好，这不是合理和正常的行为。 引用<a href="https://news.ycombinator.com/item?id=18612905">这个 HN 评论</a>的话说就是：</p>
<blockquote>
<p>Kenneth Retiz 滥用他在 PyPA 的位置（而且快速把一个实际上是 beta 状态的产品的版本号从 0 升到 18）来暗示 Pipenv 已经非常稳定，受到大力支持并且非常官方，但事实却并不是这样。</p>
</blockquote>
<p>在这篇（劝退）文章里，我会分别从包的安装、更新、卸载来测试并指出 Pipenv 的一些问题。</p>
<h2>测试准备</h2>
<ul>
<li>项目：<a href="https://github.com/greyli/bluelog">Bluelog</a>（一个 Flask 博客）</li>
<li>Pipenv 版本：2018.11.26（最新版本）</li>
<li>操作系统：Windows 10，Cmder</li>
<li>测试流程：每一次测试命令前都会删除已经创建的虚拟环境（pipenv &#8211;rm），重置 Pipfile 和 Pipfile.lock 文件变动，然后重新创建虚拟环境（pipenv install）。</li>
</ul>
<h2>安装包</h2>
<p>假设想给这个旧项目 Bluelog 添加新功能，拿到旧项目的代码，打算安装一个 Flask-Avatars 包。查了文档，发现安装包要使用 <a href="https://docs.pipenv.org/en/latest/basics/#pipenv-install">pipenv install</a> 命令，所以执行了下面的命令：</p>
<pre class="">$ pipenv install flask-avatars</pre>
<p>结果发现其他所有的不相干依赖都被更新了……</p>
<p>WTF，这不是反人类吗（说好的「Python Development Workflow for Humans.」呢）？我安装一个包，默认行为竟然是更新其他所有不相干且已经锁定版本的依赖！</p>
<p>翻了文档才发现，要加一个 &#8211;keep-outdated 选项才能避免更新其他锁定的依赖：</p>
<pre class="">$ pipenv install --help
...
--keep-outdated Keep out-dated dependencies from being updated in
Pipfile.lock. [env var: PIPENV_KEEP_OUTDATED]</pre>
<p>好吧，那先忍着，多打一个命令行选项就是了：</p>
<pre class="">$ pipenv install --keep-outdated flask-avatars</pre>
<p>WTF，为什么所有依赖还是被更新了？</p>
<p>好吧，有 bug 很正常，我来提个 issue 吧，哎，好像有很多 issue 了？</p>
<ul>
<li><a href="https://github.com/pypa/pipenv/issues/1554">install&#8217;s `&#8211;keep-outdated` does not seem to be respected</a></li>
<li><a href="https://github.com/pypa/pipenv/issues/3517">pipenv install &#8211;keep-outdated still updates packages</a></li>
</ul>
<p>重点评论：</p>
<div id="attachment_2545" style="width: 730px" class="wp-caption alignnone"><img class="wp-image-2545 size-full" src="http://greyli.com/wp-content/uploads/2019/08/pipenv-comments1.png" alt="" width="720" height="963" srcset="https://greyli.com/wp-content/uploads/2019/08/pipenv-comments1.png 720w, https://greyli.com/wp-content/uploads/2019/08/pipenv-comments1-112x150.png 112w, https://greyli.com/wp-content/uploads/2019/08/pipenv-comments1-224x300.png 224w, https://greyli.com/wp-content/uploads/2019/08/pipenv-comments1-624x835.png 624w" sizes="(max-width: 720px) 100vw, 720px" /><p class="wp-caption-text"><a href="https://github.com/pypa/pipenv/issues/1554#issuecomment-370850330">https://github.com/pypa/pipenv/issues/1554#issuecomment-370850330</a></p></div>
<p>Kenneth Reitz 先是说 lockfile 只要是过期了就总是会被重新生成（这是什么逻辑？），接着又说用 pipenv update depname，但其他人都回复不起作用（我下面会进行单独测试）。</p>
<p>接着，看到其他评论提到用 &#8211;selective-upgrade 选项：</p>
<pre class="">$ pipenv install --help
...
--selective-upgrade Update specified packages.</pre>
<p>我又继续使用 &#8211;selective-upgrade 选项：</p>
<pre class="">$ pipenv install --selective-upgrade flask-avatars</pre>
<p>仍然会更新所有依赖……</p>
<p>对了，顺便还测试了这个命令，依然没用：</p>
<pre class="">$ pipenv install --keep-outdated --selective-upgrade flask-avatars</pre>
<p>除了安装某个包会导致所有依赖版本被更新，Pipenv 在解决依赖的冲突上面也有一些不足，比如执行下面的安装命令（具体见 <a href="https://github.com/sdispater/poetry#dependency-resolution">Poetry README</a>）：</p>
<pre class="">$ pipenv install oslo.utils==1.4.0</pre>
<p>会提示无法安装成功：</p>
<pre class="">ERROR: ERROR: Could not find a version that matches pbr!=0.7,!=2.1.0,&lt;1.0,&gt;=0.6,&gt;=2.0.0</pre>
<h2>更新包</h2>
<p>假设我想更新 Bluelog 这个项目用的 Flask 版本（从 1.0.2 更新到最新的 1.1.1）。查了文档，找到了 update 命令（<a href="https://docs.pipenv.org/en/latest/basics/#example-pipenv-upgrade-workflow">https://docs.pipenv.org/en/latest/basics/#example-pipenv-upgrade-workflow</a>），于是我执行下面的命令：</p>
<pre class="">$ pipenv update flask
Locking [dev-packages] dependencies…
Success!
Locking [packages] dependencies…
Success!
Updated Pipfile.lock (fd55e3)!
Installing dependencies from Pipfile.lock (fd55e3)…
================================ 26/26 - 00:00:12
To activate this project's virtualenv, run pipenv shell.
Alternatively, run a command inside the virtualenv with pipenv run.
All dependencies are now up-to-date!</pre>
<p>突然看到最后一行赫然写着「All dependencies are now up-to-date!」，我以为是搞错了，赶紧看了下 Pipfile.lock，WTF，为什么我所有的依赖（包括和 Flask 完全不相关的）又都被更新了？<br />
依然，已经有很多相关 issue：</p>
<ul>
<li><a href="https://github.com/pypa/pipenv/issues/2665">pipenv update &lt;pkg&gt; updates all packages and not just the selected</a></li>
<li><a href="https://github.com/pypa/pipenv/issues/966">Updating only one locked dependency</a></li>
</ul>
<p>重点评论：</p>
<div id="attachment_2546" style="width: 625px" class="wp-caption alignnone"><img class="wp-image-2546 size-large" src="http://greyli.com/wp-content/uploads/2019/08/pipenv-comments2-615x1024.png" alt="" width="615" height="1024" srcset="https://greyli.com/wp-content/uploads/2019/08/pipenv-comments2-615x1024.png 615w, https://greyli.com/wp-content/uploads/2019/08/pipenv-comments2-90x150.png 90w, https://greyli.com/wp-content/uploads/2019/08/pipenv-comments2-180x300.png 180w, https://greyli.com/wp-content/uploads/2019/08/pipenv-comments2-624x1039.png 624w, https://greyli.com/wp-content/uploads/2019/08/pipenv-comments2.png 720w" sizes="(max-width: 615px) 100vw, 615px" /><p class="wp-caption-text"><a href="https://github.com/pypa/pipenv/issues/966#issuecomment-346204439">https://github.com/pypa/pipenv/issues/966#issuecomment-346204439</a></p></div>
<p>如果这个 issue 没有被锁定，这一句「I have no idea.」下面的图标不知道还会被点多少次。我猜 Kenneth Reitz 对这个 issue 让多少人头疼也没有 idea。</p>
<p>继续搜索，查文档，发现 update 命令也有 &#8211;keep-outdated 和 &#8211;selective-upgrade 两个选项：</p>
<pre class="">$ pipenv update --help 
... 
--selective-upgrade Update specified packages.
--keep-outdated Keep out-dated dependencies from being updated in
Pipfile.lock. [env var: PIPENV_KEEP_OUTDATED]</pre>
<p>先来试下 &#8211;keep-outdated：</p>
<pre class="">$ pipenv update --keep-outdated flask</pre>
<p>no luck，还是更新了所有依赖。继续试一下 &#8211;selective-upgrade：</p>
<pre class="">$ pipenv update --selective-upgrade flask</pre>
<p>依然没用，仍然会更新所有依赖……</p>
<p>继续查 issue，发现下面这些：</p>
<ul>
<li><a href="https://github.com/pypa/pipenv/issues/2412">Upgrading a dependency with &#8211;selective-upgrade doesn&#8217;t seem to work with 2018.6.25</a></li>
<li><a style="font-size: 1rem;" href="https://github.com/pypa/pipenv/issues/3461">Confusion: &#8211;keep-outdated &#8211;selective-upgrade</a></li>
</ul>
<p>在 #3461 里发现了下面这个评论：</p>
<div id="attachment_2547" style="width: 730px" class="wp-caption alignnone"><img class="wp-image-2547 size-full" src="http://greyli.com/wp-content/uploads/2019/08/pipenv-comments3.png" alt="" width="720" height="132" srcset="https://greyli.com/wp-content/uploads/2019/08/pipenv-comments3.png 720w, https://greyli.com/wp-content/uploads/2019/08/pipenv-comments3-150x28.png 150w, https://greyli.com/wp-content/uploads/2019/08/pipenv-comments3-300x55.png 300w, https://greyli.com/wp-content/uploads/2019/08/pipenv-comments3-624x114.png 624w" sizes="(max-width: 720px) 100vw, 720px" /><p class="wp-caption-text"><a href="https://github.com/pypa/pipenv/issues/3461#issuecomment-455740272">https://github.com/pypa/pipenv/issues/3461#issuecomment-455740272</a></p></div>
<p>（因为 Frost Ming 是国内的同学，也是核心维护者，说明一下，这里无意冒犯，引用这个评论只是想说明 Pipenv 现在的开发状态。）</p>
<p>这段评论的重点是「In fact, the package name passed as argument is not used at all.」。</p>
<p>也就是说，pipenv update 实际上是不接受包名称参数的。这在下面这个评论也得到了印证：</p>
<div id="attachment_2548" style="width: 730px" class="wp-caption alignnone"><img class="wp-image-2548 size-full" src="http://greyli.com/wp-content/uploads/2019/08/pipenv-comments4.png" alt="" width="720" height="569" srcset="https://greyli.com/wp-content/uploads/2019/08/pipenv-comments4.png 720w, https://greyli.com/wp-content/uploads/2019/08/pipenv-comments4-150x119.png 150w, https://greyli.com/wp-content/uploads/2019/08/pipenv-comments4-300x237.png 300w, https://greyli.com/wp-content/uploads/2019/08/pipenv-comments4-624x493.png 624w" sizes="(max-width: 720px) 100vw, 720px" /><p class="wp-caption-text"><a href="https://github.com/pypa/pipenv/issues/3461#issuecomment-493847853">https://github.com/pypa/pipenv/issues/3461#issuecomment-493847853</a></p></div>
<blockquote>
<p>Here is the important caveat:pipenv updatealwaystargets every package in your lockfile, without exception. It does not accept arguments.</p>
</blockquote>
<p>一个还没实现的功能就写到文档里了？这真的不是开玩笑吗？不仅是写到了文档里，还写到了命令行帮助文档里：</p>
<pre class="">$ pipenv update --help
Usage: pipenv update [OPTIONS] [PACKAGES]...</pre>
<p>类似下面的场景：</p>
<ul>
<li>用户：怎么运行程序呢？好，查下文档，文档里说「执行 run 命令就可以运行程序」。哎？怎么没用？</li>
<li>开发者：哦，这个功能还没实现，先写出来让你练练手。</li>
</ul>
<p>最终的结果就是，如果你想更新一个包，那就只能手动把更新版本的包版本和 hash 编辑到 Pipfile.lock 里。这么做实在是太蠢了。</p>
<h2>卸载包</h2>
<p>假设我决定不再使用 Gunicorn，需要卸载它，在文档里查到 pipenv uninstall 命令<span data-offset-key="asi8m-0-0">（</span><a class="Link ztext-link" href="https://docs.pipenv.org/en/latest/basics/#pipenv-uninstall" target="_blank" rel="noopener" data-offset-key="asi8m-1-0" data-editable="true"><span data-offset-key="asi8m-1-0">https://docs.pipenv.org/en/latest/basics/#pipenv-uninstall</span></a><span data-offset-key="asi8m-2-0">），</span>于是执行下面的命令：</p>
<pre class="">$ pipenv uninstall gunicorn</pre>
<p>结果呢？为什么我所有的依赖又都被更新了！？好，我已经习惯了。看命令行帮助文档，同样有 &#8211;keep-outdated 命令：</p>
<pre class="">$ pipenv uninstall --help
...
--keep-outdated Keep out-dated dependencies from being updated in
Pipfile.lock. [env var: PIPENV_KEEP_OUTDATED] </pre>
<p>再试一下，虽然我已经不抱期待了：</p>
<pre class="">$ pipenv uninstall --keep-outdated gunicorn</pre>
<p>顺便说一句，卸载的另一个问题是，当你卸载一个包的时候，只会卸载这个包本身，而这个包引入的相关依赖都会被保留，需要手动使用 clean 或 sync 命令修正（参考 <a href="https://github.com/sdispater/poetry#dependency-resolution">Poetry README</a>）。</p>
<h2>不要使用 Pipenv（至少是现在）</h2>
<p>当然，Pipenv 一直在改进。比如 Windows 支持，Lock 很慢的问题，都有过很多的优化（暂且不提没优化之前的痛苦经历）。</p>
<p>但是，种种证据都在表明，这其实是一个半成品。<a href="https://chriswarrick.com/blog/2018/07/17/pipenv-promises-a-lot-delivers-very-little/">承诺了很多，兑现的却很少</a>。或许过一段时间等它真正成熟了，能够保证基本使用流程，并且可以修改哪些反人类的设定以后再考虑用它（我怀疑这一条是否能实现，除非完全「去 Kenneth Reitz 化」，并且有一个核心维护者能够来推动执行）。</p>
<p>现在，请不要使用它。</p>
<p>我很抱歉在《Flask Web 开发实战》以及文章《<a href="http://greyli.com/pipenv-new-python-dependency-management-tool/">Pipenv：新一代Python项目环境与依赖管理工具</a>》中，推动更多人用它，给大家带来潜在的麻烦。我计划了一些补救措施，会逐一执行：</p>
<ul>
<li>写这篇文章【DONE】</li>
<li>给《Flask Web 开发实战》的五个实例项目追加 requirements.txt 文件，并在 README 中添加说明。</li>
<li>如果《Flask Web 开发实战》能出第二版，修改所有 Python 包安装命令，去掉所有 Pipenv 相关介绍。</li>
<li>写文章介绍替代的几种工具和用法，包括原有的 virtualenv+pip、virtualenvwrapper、Poetry 等。</li>
<li>在 PyCon China 2019 的闪电演讲《<a href="http://greyli.com/pyconchina-2019-lighting-talk-venv">Python 虚拟环境和依赖管理工具大乱斗</a>》里提及这个信息。</li>
<li>以后写推荐文章时对这种带着强烈个人风格的项目保持警惕，并对 Kenneth Reitz 这个名字相关的东西保持警惕。</li>
</ul>
<p>你可以选择用回 virtualenv+pip（+virtualenvwrapper），或是尝试新工具，我会在下一篇文章介绍主要替代品 Poetry 的基本用法。</p>
<h2>相关文章</h2>
<ul class="public-DraftStyleDefault-ul" data-offset-key="f8r7e-0-0">
<li class="Editable-styled public-DraftStyleDefault-unorderedListItem public-DraftStyleDefault-reset public-DraftStyleDefault-depth0 public-DraftStyleDefault-listLTR" data-block="true" data-editor="d4kdt" data-offset-key="f8r7e-0-0">
<div class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr" data-offset-key="f8r7e-0-0"><a class="Link ztext-link" href="https://zhuanlan.zhihu.com/p/80695813" target="_blank" rel="noopener" data-offset-key="f8r7e-0-0" data-editable="true"><span data-offset-key="f8r7e-0-0">Pipenv 有什么问题</span></a></div>
</li>
<li class="Editable-styled public-DraftStyleDefault-unorderedListItem public-DraftStyleDefault-depth0 public-DraftStyleDefault-listLTR" data-block="true" data-editor="d4kdt" data-offset-key="amab1-0-0">
<div class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr" data-offset-key="amab1-0-0"><a class="Link ztext-link" href="https://zhuanlan.zhihu.com/p/80683249" target="_blank" rel="noopener" data-offset-key="amab1-0-0" data-editable="true"><span data-offset-key="amab1-0-0">也谈「不要用 Pipenv」</span></a></div>
</li>
<li class="Editable-styled public-DraftStyleDefault-unorderedListItem public-DraftStyleDefault-depth0 public-DraftStyleDefault-listLTR" data-block="true" data-editor="d4kdt" data-offset-key="fe43v-0-0">
<div class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr" data-offset-key="fe43v-0-0"><a class="Link ztext-link" href="https://zhuanlan.zhihu.com/p/80727727" target="_blank" rel="noopener" data-offset-key="fe43v-0-0" data-editable="true"><span data-offset-key="fe43v-0-0">回应《也谈「不要用 Pipenv」》</span></a></div>
</li>
<li class="Editable-styled public-DraftStyleDefault-unorderedListItem public-DraftStyleDefault-depth0 public-DraftStyleDefault-listLTR" data-block="true" data-editor="d4kdt" data-offset-key="b5b6u-0-0">
<div class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr" data-offset-key="b5b6u-0-0"><a class="Link ztext-link" href="https://zhuanlan.zhihu.com/p/80826465" target="_blank" rel="noopener" data-offset-key="b5b6u-0-0" data-editable="true"><span data-offset-key="b5b6u-0-0">回应「回应《也谈「不要用 Pipenv」》」</span></a></div>
</li>
</ul>
<p>（1）</p>
]]></content:encoded>
			<wfw:commentRss>https://greyli.com/do-not-use-pipenv/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
