如何在不重复导入***名称的情况下构造python包

Posted

技术标签:

【中文标题】如何在不重复导入***名称的情况下构造python包【英文标题】:How to structure python packages without repeating top level name for import 【发布时间】:2013-07-01 17:18:16 【问题描述】:

我是 python 包管理的新手,肯定做错了什么。我被鼓励创建一个目录结构如下:

bagoftricks
├── bagoftricks
│   ├── bagoftricks
│   │   ├── __init__.py
│   │   └── bagoftricks.py
│   └── __init__.py
├── README.md
└── setup.py

bagoftricks.py 包含两个函数,levenshtein()geofind()

我想把它们称为:

import bagoftricks

x = bagoftricks.levenshtein(arg1,arg2) 

相反,我发现我必须这样做:

import bagoftricks

x = bagoftricks.bagoftricks.levenshtein(arg1,arg2) 

有没有更好的方法来组织我的包裹,而不用重复命名?

更新

所以,我按照下面 Avichal Badaya 的说明,移除了一层嵌套。也就是说,我现在有……

bagoftricks
├── bagoftricks
│   ├── __init__.py
│   └── bagoftricks.py
├── README.md
└── setup.py

但是,要调用这个包,我还是有...

from bagoftricks.bagoftricks import geofind()

import bagoftricks

然后

>>> bagoftricks.bagoftricks.geofind()

而不是想要的......

from bagoftricks import geofind()

import bagoftricks

>>> bagoftricks.geofind()

我无法移除额外的嵌套层。以此类推,当我尝试移除一层嵌套时,我的模块是扁平的,如下所示:

bagoftricks
├── __init__.py
├── bagoftricks.py
├── README.md
└── setup.py

我根本无法构建包...

$ python setup.py build
running build
running build_py
error: package directory 'bagoftricks' does not exist

像标准包一样使用自然导入,没有多余的***名称导入的秘诀是什么?

【问题讨论】:

【参考方案1】:

遵循以下结构:

bagoftricks 
    ── bagoftricks
    │ ├── __init__.py
    │ └── bagoftricks.py 
    ├── README.md
    └── setup.py

然后您应该可以将其用作:

from bagoftricks.bagoftricks import levenshtein, geofind

但是在您更改文件夹结构之后:-

pip uninstall <your package name mostly mentioned in setup.py>

然后重新安装包

同时检查你的 setup.py

#!/bin/env python
import os.path
from setuptools import setup, find_packages

def current_path(file_name):
    return os.abspath(os.path.join(__file__, os.path.pardir, file_name))

setup(
    name = 'bagoftricks',
    version = '0.1',
    include_package_data = True,
    packages=find_packages(),
)

setup 也可能有一些其他参数。我希望它对你有用。

【讨论】:

是否有任何配置可以让我通过一个电话来完成?只需 from bagoftricks import levenshtein, geofind 而不是子模块调用 from bagoftricks.bagoftricks import levenshtein, geofind? @Mittenchops 将from . bagoftricks import levenshtein, geofind 放入您的bagoftricks/__init__.py【参考方案2】:

第一级“bagoftricks”很好。可以这么说,这只是您的“项目”的名称。在你有一个 setup.py 和其他文件告诉打包系统他们需要知道什么。

然后您可以将代码直接放在该模块中,或者放在 src 目录中。您甚至可以只使用这种结构:

bagoftricks
├── bagoftricks.py
├── README.md
└── setup.py

但我不建议这样做,主要是因为您可能想稍后重新组织,如果您已经有一个“合适的”包会更容易。此外,大多数人、工具和文档都假设你有一个包,所以它更容易。

所以最小值是:

bagoftricks
├── bagoftricks
│   └── __init__.py
├── README.md
└── setup.py

__init__.py 包含您要导入的函数。然后你可以像这样使用这些函数:

from bagoftricks import levenshtein, anotherfunction

一旦__init__.py 变得太大,你想把它分成几个模块,给你这样的东西:

bagoftricks
├── bagoftricks
│   ├── __init__.py
│   ├── anothermodule.py
│   └── levenshtein.py
├── README.md
└── setup.py

然后您的__init__.py 应该从各个模块导入函数:

from bagoftricks.levenshtein import levenshtein
from bagoftricks.anothermodule import anotherfunction

然后你仍然可以像以前一样使用它们。

【讨论】:

谢谢,这很清楚也很有帮助,尤其是关于如何有效和正确地种植它的提示。问题肯定是我当时的 init.py 语句。我不太明白它在层次结构中的位置以及将其放在何处以缩短通话时间。完美运行。谢谢! omg,我已经写 python 很多年了,这是我第一次听说 init.py 文件可以包含一些东西!我只是让它浮动来指示哪些目录是模块的一部分!【参考方案3】:

您发布的更新结构

bagoftricks
├── bagoftricks
│   ├── __init__.py
│   └── bagoftricks.py
├── README.md
└── setup.py

into bagoftricks/__init__.py import all functions that you need

__init__.py
from bagoftricks import geofind, levenshtein

进入不同的程序,您可以执行以下操作

from bagoftricks import geofind
import bagoftricks; bagoftricks.geofind(); bagoftricks.bagoftriks.geofind()

请注意,您也可以导入通配符

from bagoftricks import *

【讨论】:

虽然导入像from module import * 这样的通配符被认为是非常糟糕的做法,因为它会导致命名空间冲突。始终尝试通过命名您导入的所有内容来导入。 是的 - 你是对的,但对于这个例子很好 - 还要注意来自 bagoftricks 的模块被导入命名空间 bagoftricks。 只是想知道;为什么这个例子很好?如果从 bagoftricks 导入 geofind,然后从另一个模块导入一个也称为 geofind 的函数,就会发生冲突。我在这里想念什么?为什么这个示例与其他 Python 代码不同?使用通配符导入是不好的做法,期间。

以上是关于如何在不重复导入***名称的情况下构造python包的主要内容,如果未能解决你的问题,请参考以下文章

如何在不重复值的情况下链接两个 jcombobox

在不知道工作表名称的情况下使用 SSIS 从 Excel 导入数据

如何在不从终端或任何编辑器执行的情况下运行 python 程序 [重复]

如何在构造函数中访问类变量以在不使用 C++ 中的 this 指针的情况下分配它们

如何在不重复的情况下配对这个数组的内容?

在不安装的情况下导入 Python 库