Java语言使用分层包名,而Python语言不使用。Java使用反向域名作为包名是一种约定,例如,对于一个Stack Overflow的Java包,代码应该放在com.stackoverflow包下。而Python的一个包却使用了类似Java的约定,这引发了人们的讨论和疑问。为什么会出现这种差异?使用哪种方式有各自的优点和缺点?这些优点和缺点是否适用于这两种语言?
2、解决方案:
有关这个问题,有以下几种观点:
-
Python不使用这种命名方式,是因为这样会产生一个问题:谁拥有几乎所有其他东西的子包的“com”包?Python通过文件系统层次结构来建立包层次结构的方法与此约定非常不兼容。Java之所以能够解决这个问题,是因为包层次结构是由传递给
package
语句的字符串文字的结构定义的,因此任何地方都不需要显式的“com”包。 -
假设Guido本人宣布应该遵循反向域名约定,除非对python中的导入实施重大更改,否则不会被采用。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_path或other_folder_on_path要么在搜索路径中更高。当Python看到from com.
时,它会抓住它能找到的第一个com包。如果恰好包含domain1,则第一个导入将成功;如果不是,它将抛出ImportError并放弃。为什么?因为导入必须在运行时发生,可能在代码流的任何一点(尽管最常见的是在开头)。在这一点上,没有人想要一个穷举的树形遍历来验证是否没有可能的匹配项。它假设如果它找到一个名为com的包,那么它就是com包。
-
Python的风格更简单。Java的风格允许不同组织具有同名的产品。您可以轻松地为Python设置顶级包,例如“com”、“org”、“mil”、“net”、“edu”和“gov”,并将您的包作为这些子包。这样做有一些复杂性,因为每个人都必须合作,并且不要用他们自己的东西污染这些顶级包。Python没有这样做,因为实际上命名冲突相当罕见。Java开始这样做,因为开发Java的人预见到许多人毫无头绪地为他们的包选择了相同的名称,并且需要解决冲突和所有权问题。
-
当Sun推出Java时,它带有轰动效应和炒作。Java应该接管一切。大多数未来的相关软件开发都将在网络交付的Java小程序上进行。在这种情况下,预先建立基于互联网、对公司友好的命名约定是合理的。随着时间的推移,Java并没有像Sun希望的那样取得成功,但这证明了他们提前为成功做准备的远见。Python最初是Guido van Rossum的一个项目,社区花了一些时间才确信如果van Rossum被公共汽车撞了,它能够生存下来。据我所知,最初没有计划要接管世界,也没有打算作为网络小程序语言。因此,在该语言的形成阶段,没有理由想要一个庞大的层次结构作为命名方案。在那个更非正式的社区中,人们选择了一个或多或少异想天开的名字,并检查是否有人已经在使用它。
-
这是一个防止名称冲突的好方法,并且充分利用了现有的域名系统,因此不需要额外的官僚机构或注册。它简单而聪明。反转域名名还赋予其层次结构,这很方便。因此,您可以在末尾放置子包。唯一的缺点是名称的长度,但对我来说这不是缺点。我认为对于任何支持它的语言来说,这是一个非常好的主意。
-
这个想法是保持命名空间无冲突。使用反向域名不容易与其他人的域名冲突。非常简单,但很实用。此外,在使用第三方库时,它可以让你知道它们来自哪里(用于更新、支持等)。
-
Python确实有分层包命名方式,但它是一个更加扁平的层次结构。例如,看看os.path。没有什么能阻止库设计者做出更深层次的命名方式,比如Django。从根本上讲,我认为Python的设计理念是,您希望在无需提前指定或键入太多内容的情况下完成任务。这极大地帮助了脚本和命令行使用。在“Python的禅意”中,有几个部分论述了这样做的理由:
简单优于复杂。
扁平优于嵌套。
美丽优于丑陋。(Java系统对我来说看起来很丑。)
另一方面,有:
命名空间是一个非常棒的想法——让我们做更多这样的事情!