避免Python中的模块名称空间污染
TL;DR:将实现细节排除在模块名称空间之外的最干净的方法是什么 在这个主题上已经有很多类似的问题,但是似乎没有一个关于现代工具和语言特性的令人满意的答案 我正在设计一个Python包,我希望保持每个模块的公共接口干净,只公开预期的内容,隐藏实现细节(尤其是导入) 多年来,我看到了许多技术: 别担心。只需记录如何使用您的包,让它的使用者忽略实现细节。 在我看来,这太可怕了。设计良好的界面应易于发现。公开实现细节会使接口更加混乱。即使是作为一个包的作者,我也不想在它暴露太多的时候使用它,因为它会使自动完成变得不那么有用 在所有实现详细信息的开头添加下划线。 这是一个很好理解的约定,大多数开发工具都足够聪明,至少可以将下划线前缀的名称排序到自动完成列表的底部。如果你有一小部分名字可以用这种方式来处理,效果很好,但是随着名字数量的增加,它变得越来越乏味和丑陋 以这个相对简单的进口清单为例:避免Python中的模块名称空间污染,python,namespaces,package,Python,Namespaces,Package,TL;DR:将实现细节排除在模块名称空间之外的最干净的方法是什么 在这个主题上已经有很多类似的问题,但是似乎没有一个关于现代工具和语言特性的令人满意的答案 我正在设计一个Python包,我希望保持每个模块的公共接口干净,只公开预期的内容,隐藏实现细节(尤其是导入) 多年来,我看到了许多技术: 别担心。只需记录如何使用您的包,让它的使用者忽略实现细节。 在我看来,这太可怕了。设计良好的界面应易于发现。公开实现细节会使接口更加混乱。即使是作为一个包的作者,我也不想在它暴露太多的时候使用它,因为它会使
导入结构
从abc导入abstractmethod,abc
从枚举导入枚举
输入import binaryo、Dict、迭代器、List、Optional、Type、Union
应用下划线技术,这个相对较小的导入列表变成了一个怪物:
import struct as\u struct
从abc导入abstractmethod作为_abstractmethod,abc作为_abc
从枚举导入枚举为_enum
从键入导入(
Binaryo作为_binaryo,
口述,
迭代器作为_迭代器,
列为_列表,
可选为_可选,
类型为_类型,
联盟即联盟
)
现在,我知道这个问题可以通过从不从导入中执行,而只是导入整个包,并对所有内容进行包限定来部分缓解。虽然这确实有助于解决这个问题,但我意识到有些人还是喜欢这样做,这并不能消除问题,我也不喜欢这样做。有一些包我更喜欢直接导入,但我通常更喜欢显式导入类型名和装饰符,以便使用它们
下划线前缀还有一个小问题。以以下公开类为例:
类小部件(\u ABC):
@_抽象方法
def implement_me(self,input:_List[int])->_Dict[str,object]:
...
实现自己的小部件
实现的此软件包的使用者将看到他需要实现implement\u me
方法,并且它需要获取\u列表
并返回\u Dict
。这些不是实际的类型名,现在实现隐藏机制已经泄漏到我的公共接口中。这不是一个大问题,但它确实导致了这个解决方案的丑陋
在函数中隐藏实现细节。
这一个肯定是黑客,它不适合大多数开发工具
下面是一个例子:
def模块():
导入结构
从abc导入abstractmethod,abc
从输入import binaryo、Dict、List
def填充列表(r:Binaryo,count:int,lst:list[int])->无:
当计数>16时:
lst.extend(struct.unpack)(“我会坚持打包并重新组织您的目录结构。如果我没有弄错的话,您可以去掉子目录中的大多数\uuuu init\uuuuuuy
文件,而是确保将根文件夹路径添加到模块查找路径(我认为它是sys.path
)。然后您可以将python模块存储在“shapes”目录中,并将其作为一个子包(然后只需从shapes import*
或您喜欢的导入版本调用)在my_包中
包。人们通常建议查看一些现有的Python包,比如-也许你会在那里找到一些有价值的东西。@KacperFloriański:我想你没有抓住我试图处理shapes
目录的要点。我正在尝试不扁平化那里的名称空间。该包将exposemyu-package.shapes.circle.circle
,myu-package.shapes.circle.Sphere
,myu-package.shapes.square.square
,等等。一般来说,我更喜欢展平我的名称空间,但在某些情况下,公开层次结构是有意义的,我想确保涵盖这种情况,特别是因为这正是my技术变得特别混乱。如果你不想在任何情况下扁平化你的结构,我认为在Python中没有比上一种方法更好的方法。但是如果我是使用你的工具的开发人员,我可能会对我需要键入4级导入感到不安-至少在你的示例中,使用e circle、square等目录。据我所知,python的方法是直接在shapes包中暴露模块。但我希望更精通专业包装的人能拯救你!
my_package/
+--__init__.py
+--_widget.py
+--shapes/
+--__init__.py
+--circle/
| +--__init__.py
| +--_circle.py
+--square/
| +--__init__.py
| +--_square.py
+--triangle/
+--__init__.py
+--_triangle.py