如何在 Python 包中正确导入子模块?
How to properly import sub-modules in a Python package?
我对如何导入和组织我的子模块有点迷茫,我需要一些文献和一些约定。
问题
我们想写一个用 Python 编写的新包,它由几个组件组成:
- 类 和对最终用户有用的功能
- 类 和很少使用的函数
- 实用程序类 和只有包本身需要的功能
- 外部模块
我们考虑这个架构:
pizzafactory
├── __init__.py
├── salt.py
├── water.py
├── vegetables
│ ├── __init__.py
│ └── tomatoes.py
└── dough
├── __init__.py
└── flour.py
一些注意事项
- 最终用户不需要使用生面团或水等原料
- 顾客只需要
pizzafactory/__init__.py
中描述的披萨
- 面团工厂需要盐和水
- 顾客可能想在比萨上加一些西红柿。
文件pizzafactory/__init__.py
需要几乎所有的模块,但是因为我们不想用无用的东西污染最终用户命名空间。除了可能被客户使用的成分外,我建议悄悄地进口成分:
# pizzafactory/__init__.py
import salt as _salt
import dough as _dough
import vegetables.tomatoes
import oven as _oven # External package
面团工厂需要一些水,但需要使用该子模块(制作面包)的用户可能不想看到 water
。
# pizzafactory/dough/__init__.py
import pizzafactory.water as _water
讨论
首先,我觉得直接导入所有内容或完整包总是更容易:
import pizzafactory
def grab_tomato():
return pizzafactory.vegetables.tomatoes.BeefsteakTomato()
或只有必需的元素:
from pizzafactory.vegetables.tomatoes import BeefsteakTomato
def grab_tomato():
return BeefsteakTomato()
这两种方法都很常见,但它可能会污染 pizzafactory
命名空间,因此最好将导入名称弄乱。我意识到没有人这样做,我也不知道为什么。
问题
在这个通用示例中,我想知道如何正确导入模块、子模块和外部包,以便:
- 最小化命名空间足迹
- 帮助最终用户清楚地看到他打算使用的东西
Both of these methods are common, but it may pollute the pizzafactory namespace, so it may be preferable to mangle the import names. I relalized that nobody does that and I don't know why.
Python 是一种同意的成人语言,在大多数情况下,我们不锁门,一切都公开。
如果您只是担心名称空间太拥挤,您应该定义 __all__
并使用单前导下划线。 -- PEP8 建议名称修改应该只用于避免命名冲突,所以这可能就是为什么没有人这样做的原因。
查看 Public and internal interfaces section of PEP8 as well as Naming Convensions.
PEP8 是 "proper" 做这些事情的指南。虽然,它是 指南 不一定是 法律。你可以灵活地做你认为适合你的包的事情,这导致了我最喜欢的 PEP8 部分 - A Foolish Consistency is the Hobgoblin of Little Minds
如果不充分了解包中的代码,可能无法提供超出 PEP8 的更多建议应该如何完成。如果你有时间,Raymond Hettinger 的演讲 Beyond PEP 8 值得一看。
我对如何导入和组织我的子模块有点迷茫,我需要一些文献和一些约定。
问题
我们想写一个用 Python 编写的新包,它由几个组件组成:
- 类 和对最终用户有用的功能
- 类 和很少使用的函数
- 实用程序类 和只有包本身需要的功能
- 外部模块
我们考虑这个架构:
pizzafactory
├── __init__.py
├── salt.py
├── water.py
├── vegetables
│ ├── __init__.py
│ └── tomatoes.py
└── dough
├── __init__.py
└── flour.py
一些注意事项
- 最终用户不需要使用生面团或水等原料
- 顾客只需要
pizzafactory/__init__.py
中描述的披萨
- 面团工厂需要盐和水
- 顾客可能想在比萨上加一些西红柿。
文件pizzafactory/__init__.py
需要几乎所有的模块,但是因为我们不想用无用的东西污染最终用户命名空间。除了可能被客户使用的成分外,我建议悄悄地进口成分:
# pizzafactory/__init__.py
import salt as _salt
import dough as _dough
import vegetables.tomatoes
import oven as _oven # External package
面团工厂需要一些水,但需要使用该子模块(制作面包)的用户可能不想看到 water
。
# pizzafactory/dough/__init__.py
import pizzafactory.water as _water
讨论
首先,我觉得直接导入所有内容或完整包总是更容易:
import pizzafactory
def grab_tomato():
return pizzafactory.vegetables.tomatoes.BeefsteakTomato()
或只有必需的元素:
from pizzafactory.vegetables.tomatoes import BeefsteakTomato
def grab_tomato():
return BeefsteakTomato()
这两种方法都很常见,但它可能会污染 pizzafactory
命名空间,因此最好将导入名称弄乱。我意识到没有人这样做,我也不知道为什么。
问题
在这个通用示例中,我想知道如何正确导入模块、子模块和外部包,以便:
- 最小化命名空间足迹
- 帮助最终用户清楚地看到他打算使用的东西
Both of these methods are common, but it may pollute the pizzafactory namespace, so it may be preferable to mangle the import names. I relalized that nobody does that and I don't know why.
Python 是一种同意的成人语言,在大多数情况下,我们不锁门,一切都公开。
如果您只是担心名称空间太拥挤,您应该定义 __all__
并使用单前导下划线。 -- PEP8 建议名称修改应该只用于避免命名冲突,所以这可能就是为什么没有人这样做的原因。
查看 Public and internal interfaces section of PEP8 as well as Naming Convensions.
PEP8 是 "proper" 做这些事情的指南。虽然,它是 指南 不一定是 法律。你可以灵活地做你认为适合你的包的事情,这导致了我最喜欢的 PEP8 部分 - A Foolish Consistency is the Hobgoblin of Little Minds
如果不充分了解包中的代码,可能无法提供超出 PEP8 的更多建议应该如何完成。如果你有时间,Raymond Hettinger 的演讲 Beyond PEP 8 值得一看。