为什么像Java这样的语言使用分层包名,而Python却没有?

时间:2009-04-02 09:45:14

标签: java python packages

我还没有用Java做过企业工作,但我经常看到reverse-domain-name package naming convention。例如,对于Stack Overflow Java包,您将代码放在包com.stackoverflow下面。

我刚刚遇到了一个使用类似Java的约定的Python包,我不确定支持和支持它的参数是什么,或者它们是否以与Java相同的方式应用于Python。你偏爱另一个的原因是什么? 这些原因是否适用于各种语言?

8 个答案:

答案 0 :(得分:18)

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

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

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

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

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

答案 1 :(得分:13)

如果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

其中一个陈述将成功。为什么?因为folder_on_pathother_folder_on_path在搜索路径上更高。当python看到from com.时,它会抓取第一个com包。如果恰好包含domain1,则第一个import将成功;如果没有,它会抛出ImportError并放弃。为什么?因为import必须在运行时发生,可能在代码流中的任何一点(尽管通常在开头)。在那一点上,没有人想要一个详尽的树木行走来验证没有可能的匹配。它假设如果找到名为com的包,则它是 com包。

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

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

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

现在,如果分发的每个python包都需要一个搜索com文件夹的安装过程,然后是domain,那么你可以侥幸逃脱这个等等,但这会使包装变得更加困难,破坏拖放能力,并使包装和全面滋扰。

答案 2 :(得分:12)

“你偏爱另一个的原因是什么?”

Python的风格更简单。 Java的风格允许来自不同组织的同名产品。

“这些原因是否适用于各种语言?”

是。您可以轻松拥有名为“com”,“org”,“mil”,“net”,“edu”和“gov”的顶级Python包,并将您的包作为子包放在这些包中。

修改即可。当你这样做时,你会有一些复杂性,因为每个人必须合作,而不是用他们自己的副本污染这些顶级软件包。

Python没有开始这样做,因为命名空间冲突 - 实际上 - 变得相当罕见。

Java开始这样做是因为开发Java的人预见到很多人会毫不犹豫地为他们的包选择相同的名称,并且需要解决冲突和所有权问题。

Java人们没有预见到开源社区会选择奇怪的非常独特的名称以避免名称冲突。有趣的是,编写xml解析器的每个人都不会将其称为“解析器”。他们似乎把它称为“撒克逊人”或“Xalan”或者完全奇怪的东西。

答案 3 :(得分:11)

这是防止名称冲突的好方法,并充分利用现有的域名系统,因此不需要额外的官僚作风或注册。它简单而精彩。

通过反转域名,它也为它提供了一个层次结构,这很方便。所以你最后可以有子包。

唯一的缺点是名称的长度,但对我来说这根本不是缺点。对于任何支持它的语言,我认为这是一个非常好的主意。

为什么JavaScript库没有这样做呢?它们的全局命名空间是一个大问题,但Javascript库使用简单的全局标识符,如'$',它与其他Javascript库冲突。

答案 4 :(得分:11)

在Joel on Software的某个地方,Joel对两种发展公司的方法进行了比较:Ben&杰瑞的方法,从小规模开始,有机增长,以及从一开始就筹集了大量资金并投入大量资金的亚马逊方法。

当Sun推出Java时,它就是大肆宣传和炒作。 Java应该接管。大多数未来相关的软件开发将在Web提供的Java小程序上进行。会有铜管乐队甚至小马。在这种情况下,预先建立一个基于互联网,公司友好和全球范围的命名惯例是明智的。

好吧,它并没有像Sun所希望的那样,但他们计划好像他们会成功。就个人而言,我鄙视可能因成功而受损的项目。

Python最初是由Guido van Rossum开发的一个项目,并且在社区确信如果van Rossum被公共汽车击中之后,它已经有一段时间了。据我所知,没有初步计划接管这个世界,它并不是一个网络applet语言。

因此,在语言的形成阶段,没有理由要求命名方案有大量的层次结构。在那个更加非正式的社区中,人们选择了一个或多或少的异想天开的项目名称并检查其他人是否已经在使用它。 (在英国喜剧节目之后命名一种计算机语言可能会被认为是异想天开的。)没有人认为需要迎合一个大而缺乏想象力和笨拙的命名方案。

答案 5 :(得分:6)

这个想法是保持名称空间无冲突。而不是不可读的UUID等,反向域名不太可能以别人的方式进入。 很简单,但务实。 此外,当使用第三方库时,它可能会告诉您它们来自何处(更新,支持等)。

答案 6 :(得分:2)

Python 确实拥有它,它只是一个更平坦的层次结构。例如,查看os.path。并且没有什么可以阻止图书馆设计师做出更深层次的,例如Django的。

从根本上说,我认为Python的设计理念是你想要完成工作而不必事先指定或输入太多。这极大地有助于脚本和命令行使用。 “The Zen of Python”的几个部分解决了这个理由:

  • 简单比复杂更好。
  • Flat比嵌套好。
  • 美丽胜过丑陋。 (Java系统看起来很难看。)

另一方面,有:

  • 命名空间是一个很好的主意 - 让我们做更多的事情!

答案 7 :(得分:0)

Java能够像这样做,因为它是推荐的Java标准实践,并且几乎被Java社区普遍接受。 Python dos没有这个约定。