gpt4 book ai didi

python模块导入 - 相对路径问题

转载 作者:行者123 更新时间:2023-12-03 04:46:29 27 4
gpt4 key购买 nike

我正在用 python 2.7 开发我自己的模块。它位于 ~/Development/.../myModule而不是 /usr/lib/python2.7/dist-packages/usr/lib/python2.7/site-packages .内部结构为:

/project-root-dir
/server
__init__.py
service.py
http.py
/client
__init__.py
client.py
client/client.py包括 PyCachedClient类(class)。我遇到了导入问题:
project-root-dir$ python
Python 2.7.2+ (default, Jul 20 2012, 22:12:53)
[GCC 4.6.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from server import http
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "server/http.py", line 9, in <module>
from client import PyCachedClient
ImportError: cannot import name PyCachedClient

我没有设置 PythonPath 来包含我的 project-root-dir ,因此当 server.http 尝试包含 client.PyCachedClient 时,它尝试从相对路径加载它并失败。我的问题是 - 我应该如何以良好的 Pythonic 方式设置所有路径/设置?我知道我可以跑 export PYTHONPATH=...每次我打开控制台并尝试运行我的服务器时都在 shell 中,但我想这不是最好的方法。如果我的模块是通过 PyPi(或类似的东西)安装的,我会将它安装在 /usr/lib/python... 中路径,它会自动加载。

我很感激有关 Python 模块开发最佳实践的提示。

最佳答案

我的 Python 开发工作流程

这是开发 Python 包的基本过程,其中包含了我认为是社区中的最佳实践。这是基本的——如果你真的很认真地开发 Python 包,那么它还有更多的东西,每个人都有自己的偏好,但它应该作为一个模板来开始,然后更多地了解所涉及的部分。基本步骤是:

  • 使用 virtualenv 用于隔离
  • setuptools 用于创建可安装包和管理依赖项
  • python setup.py develop在开发模式下安装该软件包

  • 虚拟环境

    首先,我建议使用 virtualenv 获得一个隔离的环境来开发你的包。在开发过程中,你需要安装、升级、降级和卸载你的包的依赖项,你不希望
  • 你的开发依赖会污染你的系统范围 site-packages
  • 您的系统范围 site-packages影响您的开发环境
  • 版本冲突

  • 污染整个系统 site-packages不好,因为您在那里安装的任何包都可用于您安装的所有使用系统 Python 的 Python 应用程序,即使您的小项目只需要该依赖项。它刚刚安装在一个新版本中,该版本覆盖了系统范围内的版本 site-packages ,并且与依赖它的 ${important_app} 不兼容。你明白了。

    拥有您的系统范围 site-packages影响你的开发环境是不好的,因为也许你的项目依赖于你已经在系统 Python 中获得的模块 site-packages .因此,您忘记正确声明您的项目依赖于该模块,但一切正常,因为它始终存在于您的本地开发框中。直到您发布您的软件包并且人们尝试安装它,或将其推送到生产环境,等等......在干净的环境中开发迫使您正确声明您的依赖项。

    所以,一个 virtualenv 是一个独立的环境,有自己的 Python 解释器和模块搜索路径。它基于您之前安装的 Python 安装,但与它隔离。

    要创建 virtualenv,请安装 virtualenv通过使用 easy_install 将其安装到系统范围的 Python 来打包或 pip :

    sudo pip install virtualenv

    请注意,这将是您唯一一次以 root 身份(使用 sudo)安装某些东西到您的全局站点包中。这之后的一切都将发生在您将要创建的 virtualenv 中。

    现在创建一个用于开发包的 virtualenv:

    cd ~/pyprojects
    virtualenv --no-site-packages foobar-env

    这将创建一个目录树 ~/pyprojects/foobar-env ,这是您的 virtualenv。

    要激活 virtualenv, cd进入它和 source bin/activate script :

    ~/pyprojects $ cd foobar-env/
    ~/pyprojects/foobar-env $ . bin/activate
    (foobar-env) ~/pyprojects/foobar-env $

    注意前导点 . ,这是 source 的简写 shell 命令。还要注意提示是如何变化的: (foobar-env)意味着您在激活的 virtualenv 内部(并且始终需要隔离才能工作)。因此,每次打开新的终端选项卡或 SSH session 等时,请激活您的 env。

    如果您现在运行 python在那个激活的环境中,它实际上会使用 ~/pyprojects/foobar-env/bin/python作为口译员,拥有自己的 site-packages和隔离模块搜索路径。

    一个安装工具包

    现在用于创建您的包。基本上你会想要一个 setuptools包装带有 setup.py正确声明包的元数据和依赖项。您可以按照 setuptools documentation 自行完成此操作。 ,或使用 Paster templates 创建包骨架.要使用 Paster 模板,请安装 PasteScript进入你的虚拟环境:

    pip install PasteScript

    让我们为我们的新包创建一个源目录以保持组织有序(也许您想将您的项目分成几个包,或者稍后使用源中的依赖项):

    mkdir src
    cd src/

    现在创建你的包,做

    paster create -t basic_package foobar

    并回答交互界面中的所有问题。大多数是可选的,只需按 ENTER 即可保留默认值。

    这将创建一个名为 foobar 的包(或更准确地说,是一个 setuptools 发行版)。 .这是那个名字
  • 人们将使用 easy_install 来安装您的软件包或 pip install foobar
  • setup.py 中其他软件包将使用的名称取决于您的软件包
  • 将在 PyPi 上调用什么

  • 在内部,您几乎总是创建一个名为相同的 Python 包(如“具有 __init__.py 的目录)。这不是必需的,顶级 Python 包的名称可以是任何有效的包名称,但这是一个常见约定将其命名为与发行版相同的名称。这就是为什么将两者分开很重要但并不总是容易的原因。因为顶级 python 包名称是什么
  • 人们(或您)将使用 import foobar 导入您的包或 from foobar import baz

  • 因此,如果您使用了粘贴模板,它已经为您创建了该目录:

    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))

    还有一个 client.py在使用 models.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

    声明对 requests 的依赖模块在 setup.py :

      install_requires=[
    # -*- Extra requirements: -*-
    '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.

    将您的软件包安装为开发蛋

    现在是时候在开发模式下安装你的包了:

    python setup.py develop

    这将安装 requests依赖和你的包作为开发蛋。所以它链接到你的 virtualenv 的站点包,但仍然存在于 src/foobar您可以在其中进行更改并使它们立即在 virtualenv 中处于事件状态,而无需重新安装您的软件包。

    现在对于您的原始问题,使用相对路径导入:我的建议是,不要这样做。既然您已经有了一个合适的 setuptools 包,它已经安装并且可以导入,那么您当前的工作目录就不再重要了。就做 from foobar.models import Page或类似的,声明该对象所在的完全限定名称。这使您的源代码更具可读性和可发现性,对于您自己和其他阅读您代码的人来说。

    您现在可以通过执行 python client.py 来运行您的代码从激活的 virtualenv 中的任何位置。 python src/foobar/foobar/client.py工作正常,您的软件包已正确安装,您的工作目录不再重要。

    如果您想更进一步,您甚至可以为 CLI 脚本创建一个 setuptools 入口点。这将创建一个 bin/something您可以从 shell 运行的 virtualenv 中的脚本。

    setuptools console_scripts 入口点

    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 .

    一旦你(或其他人)在 virtualenv 之外真实地安装了你的包,入口点将在 /usr/local/bin/run-foo或类似的地方,它将自动位于 $PATH .

    进一步的步骤
  • 创建包的版本并上传 PyPi,例如使用 zest.releaser
  • 保持更新日志和版本控制你的包
  • 了解 declaring dependencies
  • 了解 Differences between distribute, distutils, setuptools and distutils2

  • 推荐阅读:
  • The Hitchhiker’s Guide to Packaging
  • The pip cookbook
  • 关于python模块导入 - 相对路径问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27406957/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com