我的Python开发工作流程
这是一个基本的Python包开发流程,结合了我认为社区最佳实践。如果您真的很认真地开发Python包,还有更多要考虑的细节,而且每个人都有自己的喜好,但它应该是一个模板,可以帮助您开始并学习其中的组件。基本步骤如下:
virtualenv
首先,我建议使用virtualenv
获取隔离环境来开发您的包。在开发过程中,您需要安装、升级、降级和卸载您包的依赖项,您不希望这些操作影响到其他项目或系统。使用virtualenv可以让你在一个单独的环境中安装Python和其他依赖,避免版本冲突和其他问题。
- 避免污染系统范围内的
site-packages
,因为您在那里安装的任何包都将对使用系统Python的所有Python应用程序可用,即使您只需要该依赖项进行小型项目。并且它刚刚以新版本安装,覆盖了系统范围内的site-packages
中的一个版本,并且与依赖于它的${important_app}不兼容。你明白了。
- 让系统范围内的
site-packages
影响开发环境也是不好的,因为您的项目可能依赖于系统Python的site-packages
中已有的模块。因此,您忘记正确声明您的项目依赖于该模块,但一切正常,因为它始终存在于您的本地开发框中。直到您发布软件包并尝试安装它或将其推向生产等...在干净的环境中开发可以强制您正确声明依赖项。
- 版本冲突
所以,一个虚拟环境是一个具有独立的Python解释器和模块搜索路径的隔离环境。它基于你之前安装的Python,但与其相互隔离。
要创建一个虚拟环境,请使用easy_install或pip将virtualenv包安装到您系统范围内的Python中:
sudo pip install virtualenv
请注意,这将是您作为root(使用sudo)安装东西到全局site-packages的
唯一时间。此后,所有操作都将在您即将创建的virtualenv中进行。
现在为开发您的软件包创建一个virtualenv:
cd ~/pyprojects
virtualenv --no-site-packages foobar-env
这将创建一个目录树
~/pyprojects/foobar-env
,它是您的虚拟环境。
要激活虚拟环境,请
cd
进入该目录并
source
bin/activate脚本
:
~/pyprojects $ cd foobar-env/
~/pyprojects/foobar-env $ . bin/activate
(foobar-env) ~/pyprojects/foobar-env $
注意前导点.
,它是source
shell命令的简写。还要注意提示符如何更改:(foobar-env)
表示您在已激活的virtualenv内部(始终需要这样才能实现隔离)。因此,每次打开新的终端选项卡或SSH会话等都要激活您的环境。
如果您现在在已激活的环境中运行python
,它实际上将使用~/pyprojects/foobar-env/bin/python
作为解释器,具有自己的site-packages
和隔离的模块搜索路径。
一个setuptools包
现在开始创建您的包。基本上,您需要一个带有setup.py
的setuptools
包来正确声明您的包的元数据和依赖项。您可以通过遵循setuptools文档自己完成此操作,也可以使用Paster templates创建包骨架。要使用Paster模板,请将PasteScript
安装到您的虚拟环境中:
pip install PasteScript
让我们为新包创建一个源目录,以保持组织有序(也许您想将项目分成几个包,或稍后从源中使用依赖项):
mkdir src
cd src/
现在创建您的软件包,请执行以下操作:
paster create -t basic_package foobar
在交互界面中回答所有问题。大多数问题都是可选的,只需按ENTER键将其保留为默认值即可。
这将创建一个软件包(或更准确地说,一个setuptools分发),名为foobar
。
- 人们将使用
easy_install
或pip install foobar
来安装您的软件包
- 其他软件包将使用该软件包名称在
setup.py
中依赖于您的软件包
- 它将在PyPi上被称为什么
通常,在内部创建一个Python软件包(即“具有__init__.py
的目录”)。这不是必需的,顶级Python软件包的名称可以是任何有效的软件包名称,但通常惯例是将其命名为与分发名称相同。这就是为什么保持两者分开很重要但不总是容易的原因。因为顶级Python软件包名称是:
- 人们(或您)将使用
import foobar
或from foobar import baz
导入您的软件包
如果您使用了paster模板,它已经为您创建了该目录:
cd foobar/foobar/
现在创建你的代码:
vim models.py
models.py
class Page(object):
"""A dumb object wrapping a webpage.
"""
def __init__(self, content, url):
self.content = content
self.original_url = url
def __repr__(self):
return "<Page retrieved from '%s' (%s bytes)>" % (self.original_url, len(self.content))
在同一目录下有一个使用models.py
的client.py
:
client.py
import requests
from foobar.models import Page
url = 'http://www.stackoverflow.com'
response = requests.get(url)
page = Page(response.content, url)
print page
在 setup.py
中声明对 requests
模块的依赖:
install_requires=[
'setuptools',
'requests',
],
版本控制
src/foobar/
是你现在想要放入版本控制的目录:
cd src/foobar/
git init
vim .gitignore
.gitignore
*.egg-info
*.py[co]
git add .
git commit -m 'Create initial package structure.
将你的包作为开发egg进行安装
现在是时候以开发模式安装你的包了:
python setup.py develop
这将安装
requests
依赖项和
您的包作为开发egg。因此,它链接到您的虚拟环境的site-packages,但仍然位于
src/foobar
,您可以在其中进行更改,并使其立即在虚拟环境中生效,而无需重新安装您的包。
现在回答您最初的问题,使用相对路径导入:我的建议是不要这样做。现在您已经有了一个合适的setuptools包,已安装并可导入,您当前的工作目录就不再重要了。只需声明该对象所在的完全限定名称,例如
from foobar.models import Page
或类似方式即可。这使得您的源代码对您自己以及阅读您代码的其他人来说更加易读和易于发现。
现在,您可以通过在激活的虚拟环境中的任何位置执行
python client.py
来运行代码。
python src/foobar/foobar/client.py
同样有效,您的包已正确安装,您的工作目录不再重要。
如果您想更进一步,甚至可以为CLI脚本创建setuptools入口点。这将在您的虚拟环境中创建一个
bin/something
脚本,您可以从shell中运行它。
setuptools控制台脚本入口点
setup.py
entry_points='''
# -*- Entry points: -*-
[console_scripts]
run-fooobar = foobar.main:run_foobar
''',
client.py
def run_client():
main.py
from foobar.client import run_client
def run_foobar():
run_client()
重新安装您的软件包以激活入口点:
python setup.py develop
然后你就可以使用 bin/run-foo
了。
一旦你(或其他人)在虚拟环境之外真正安装了你的包,入口点将在 /usr/local/bin/run-foo
或类似位置,这样它就会自动在 $PATH
中。
进一步的步骤
建议阅读:
virtualenv
进行隔离,使用setuptools
创建可安装的软件包并管理依赖项,使用python setup.py develop
在开发模式下安装该软件包。我正在撰写一个答案,尝试给出如何将这些概念结合在一起的示例。哦 - 不要使用相对导入,你很少需要它们。 - Lukas Graf