为什么像Java这样的语言使用分层包名称,而Python则不然?[已关闭]

2022-09-03 08:22:34

我没有在Java中做过企业工作,但我经常看到反向域名包命名约定。例如,对于 Stack Overflow Java 包,您可以将代码放在包的下面。com.stackoverflow

我刚刚遇到了一个使用类似Java的约定的Python包,我不确定支持和反对它的论据是什么,或者它们是否以与Java相同的方式适用于Python。您更喜欢其中一个的原因是什么?这些原因是否适用于各种语言?


答案 1

Python不会这样做,因为你最终会遇到一个问题 - 谁拥有“com”包,几乎所有其他东西都是子包?Python建立包层次结构的方法(通过文件系统层次结构)根本不适合这个约定。Java可以逃脱它,因为包层次结构是由馈送到'package'语句的字符串文本的结构定义的,所以不需要在任何地方都有一个明确的“com”包。

还有一个问题是,如果您想公开发布一个软件包,但没有一个适合进入软件包名称的域名,或者由于某种原因最终更改(或丢失)您的域名,该怎么办。(以后的更新是否需要不同的程序包名称?你怎么知道com.nifty_consultants.nifty_utility是com.joe_blow_software.nifty_utility的较新版本?或者,相反,你怎么知道它不是一个更新的版本?如果您错过了域名续订,并且该名称被域名露营者抢走,并且其他人从他们那里购买了该名称,并且他们想要公开发布软件包,那么他们是否应该使用您已经使用的相同名称?

在我看来,域名和软件包名称解决了两个完全不同的问题,并且具有完全不同的复杂因素。我个人不喜欢Java的约定,因为(恕我直言)它违反了关注点分离。避免命名空间冲突固然很好,但我讨厌我的软件命名空间是由营销部门与某些第三方官僚机构交互(并依赖于)定义的。

为了进一步澄清我的观点,为了回应JeeBee的评论:在Python中,包是一个包含文件(大概是一个或多个模块文件)的目录。包层次结构要求每个较高级别的包都是完整、合法的包。如果两个包(特别是来自不同供应商的包,但来自同一供应商的不直接相关的包)共享一个顶级包名称,无论该名称是“com”或“web”或“utils”还是其他名称,每个包都必须为该顶级包提供一个。我们还必须假设这些软件包很可能安装在目录树中的同一位置,即 site-packages/[pkg]/[subpkg]。因此,文件系统强制要求只有一个 -- 那么哪一个赢了呢?这个问题没有(也不可能)一个一般情况下的正确答案。我们也不能合理地将这两个文件合并在一起。由于我们无法知道另一个包可能需要做什么,因此在安装两个包时,不能假设共享顶级包的子包可以工作,除非它们被专门编写为彼此兼容(至少在这一个文件中)。这将是一场分发的噩梦,并且几乎会使嵌套包的整个点失效。这并不是特定于反向域名包层次结构的,尽管它们提供了最明显的坏例子,并且(IMO)在哲学上是有问题的 - 这实际上是共享顶级包的实际问题,而不是哲学问题,这是我在这里主要关注的问题。__init__.py__init__.py[pkg]/__init__.py__init__.py

(另一方面,使用子包来更好地组织自身的单个大包是一个好主意,因为这些子包专门为一起工作和生活而设计的。然而,这在Python中并不常见,因为单个概念包往往不需要足够多的文件来需要额外的组织层。


答案 2

如果Guido自己宣布应该遵循反向域约定,除非python的实现有重大变化,否则它不会被采用。import

考虑一下:python在运行时使用快速失败算法搜索导入路径;java 在编译时和运行时都使用详尽的算法搜索路径。来吧,尝试像这样排列你的目录:

folder_on_path/
    com/
        __init__.py
        domain1/
            module.py
            __init__.py


other_folder_on_path/
    com/
        __init__.py
        domain2/
            module.py
            __init__.py

然后尝试:

from com.domain1 import module
from com.domain2 import module

其中一个声明将成功。为什么?因为搜索路径上的任何一个或都更高。当python看到它时,它会抓住它能抓取的第一个包。如果碰巧包含 ,则第一个将成功;如果没有,它会抛出一个并放弃。为什么?因为必须在运行时发生,可能在代码流中的任何一点发生(尽管最常见于开头)。没有人希望在这一点上进行详尽的树行走来验证没有可能的匹配。它假设如果它找到一个名为 的包,它就是这个包。folder_on_pathother_folder_on_pathfrom com.comdomain1importImportErrorimportcomcom

此外,python不区分以下语句:

from com import domain1
from com.domain1 import module
from com.domain1.module import variable

验证的概念在每种情况下都会有所不同。在java中,您实际上只需要处理第二种情况,这可以通过遍历文件系统来完成(我猜命名类和文件具有相同的优势)。在python中,如果你试图在只有文件系统帮助的情况下完成导入,第一种情况可以(几乎)透明地相同(init.py不会运行),第二种情况可以完成,但你会失去 module.py 的初始运行,但第三种情况是完全无法实现的。代码必须执行 才能可用。这是另一个要点:它执行的不仅仅是解析命名空间,它还执行代码。comcomvariableimport

现在,如果分发的每个python包都需要一个搜索文件夹的安装过程,然后是,依此类推,那么你可以逃脱这个麻烦,但是这使得打包变得相当困难,破坏了拖放功能,并使打包和全面滋扰。comdomain