Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/asp.net/33.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
避免Python中的模块名称空间污染_Python_Namespaces_Package - Fatal编程技术网

避免Python中的模块名称空间污染

避免Python中的模块名称空间污染,python,namespaces,package,Python,Namespaces,Package,TL;DR:将实现细节排除在模块名称空间之外的最干净的方法是什么 在这个主题上已经有很多类似的问题,但是似乎没有一个关于现代工具和语言特性的令人满意的答案 我正在设计一个Python包,我希望保持每个模块的公共接口干净,只公开预期的内容,隐藏实现细节(尤其是导入) 多年来,我看到了许多技术: 别担心。只需记录如何使用您的包,让它的使用者忽略实现细节。 在我看来,这太可怕了。设计良好的界面应易于发现。公开实现细节会使接口更加混乱。即使是作为一个包的作者,我也不想在它暴露太多的时候使用它,因为它会使

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
目录的要点。我正在尝试不扁平化那里的名称空间。该包将expose
myu-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