我没有在Java中完成企业工作,但我经常看到反向域名包命名约定.例如,对于Stack Overflow Java包,您将代码放在包下面com.stackoverflow
.
我刚刚遇到了一个使用类似Java的约定的Python包,我不确定支持和支持它的参数是什么,或者它们是否以与Java相同的方式应用于Python.你偏爱另一个的原因是什么?这些原因是否适用于各种语言?
Python没有这样做,因为你最终遇到了一个问题 - 谁拥有"com"包几乎所有其他东西都是一个子包?Python建立包层次结构(通过文件系统层次结构)的方法根本不适合这种约定.Java可以逃脱它,因为包层次结构是由提供给'package'语句的字符串文字的结构定义的,所以不需要在任何地方都有一个明确的"com"包.
还有一个问题是,如果您想公开发布一个软件包但不拥有适合包含名称的域名,或者您最终因某种原因更改(或丢失)您的域名,该怎么办.(以后的更新是否需要不同的软件包名称?你怎么知道com.nifty_consultants.nifty_utility是较新版本的com.joe_blow_software.nifty_utility?或者,相反,你怎么知道它不是更新的版本?如果你想念你的域名更新和名称被域名营销者抢走,其他人从他们那里购买名称,并且他们想要公开发布软件包,如果他们使用的名称与您已经使用过的名称相同?)
在我看来,域名和软件包名称解决了两个完全不同的问题,并且具有完全不同的复杂因素.我个人不喜欢Java的惯例,因为(恕我直言)它违反了关注点的分离.避免命名空间冲突很好,但我讨厌我的软件命名空间由营销部门与某些第三方官僚机构的交互定义(并依赖于).
为了进一步澄清我的观点,回应JeeBee的评论:在Python中,包是一个包含__init__.py
文件的目录(可能是一个或多个模块文件).包层次结构要求每个更高级别的包都是完整的合法包.如果两个软件包(特别是来自不同供应商,甚至来自同一供应商的非直接相关软件包)共享顶级软件包名称,无论该名称是"com","web"还是"utils"或其他什么,每个必须提供一个__init__.py
顶级包.我们还必须假设这些包可能安装在目录树中的相同位置,即site-packages/[pkg]/[subpkg].因此文件系统强制只有一个 [pkg]/__init__.py
- 所以哪一个获胜?没有(也可能不是)该问题的一般情况正确答案.我们也不能将这两个文件合理地合并在一起.由于我们无法知道另一个软件包可能需要做什么,因此__init__.py
在安装两个软件包时,不能认为共享顶级软件包的子软件包有效,除非它们是专门编写为彼此兼容的(至少在这一个文件中) ).这将是一个分配的噩梦,并且几乎使嵌套包的整个点无效.这不是特定于反向域名包的层次结构,尽管它们提供了最明显的坏例子,而且(IMO)在哲学上是有问题的 - 它实际上是共享顶级包的实际问题,而不是哲学问题,我主要担心的是
(另一方面,使用子包来更好地组织自己的单个大包是一个好主意,因为这些子包是专门设计为一起工作和生活的.虽然这在Python中并不常见,因为单个概念包没有'往往需要足够多的文件才能需要额外的组织层.)
如果Guido自己宣布应遵循反向域约定,则不会采用,除非import
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
,那么第一个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
"你偏爱另一个的原因是什么?"
Python的风格更简单.Java的风格允许来自不同组织的同名产品.
"这些理由是否适用于各种语言?"
是.您可以轻松拥有名为"com","org","mil","net","edu"和"gov"的顶级Python包,并将您的包作为子包放在这些包中.
编辑.当你这样做时,你会有一些复杂性,因为每个人都必须合作,而不是用他们自己的手段污染这些顶级软件包.
Python没有开始这样做,因为命名空间冲突 - 实际上 - 变得相当罕见.
Java开始这样做是因为开发Java的人预见到很多人会毫无道理地为他们的包选择相同的名称,并需要解决冲突和所有权问题.
Java人们没有预见到开源社区会选择奇怪的非常独特的名称以避免名称冲突.有趣的是,编写xml解析器的每个人都不会将其称为"解析器".他们似乎把它称为"撒克逊人"或"Xalan"或者完全奇怪的东西.
这是一种防止名称冲突的好方法,并充分利用现有的域名系统,因此不需要额外的官僚作风或注册.它简单而精彩.
通过反转域名,它也为它提供了一个层次结构,这很方便.所以你可以在最后有子包.
唯一的缺点是名称的长度,但对我来说这根本不是一个缺点.对于任何支持它的语言,我认为这是一个非常好的主意.
例如,为什么JavaScript库没有这样做呢?它们的全局命名空间是一个大问题,但Javascript库使用简单的全局标识符,如'$',它与其他Javascript库冲突.
在Joel on Software的某个地方,Joel对两种发展公司的方法进行了比较:Ben&Jerry的方法,从小规模开始并有机增长,以及亚马逊筹集大量资金并从一开始就提出广泛诉求的方法.
当Sun引入Java时,它就是大肆宣传和炒作.Java应该接管.大多数未来相关的软件开发将在Web提供的Java小程序上进行.会有铜管乐队甚至小马.在这种情况下,事先建立一个基于互联网,公司友好和全球范围的命名惯例是明智的.
好吧,它并没有像Sun所希望的那样,但他们计划好像他们会成功.就个人而言,我鄙视可能因成功而破坏的项目.
Python最初是由Guido van Rossum开发的一个项目,并且在社区确信如果van Rossum被公共汽车击中之后,它还有一段时间可以生存.据我所知,没有最初的计划来接管这个世界,它并不是一个网络applet语言.
因此,在语言的形成阶段,没有理由要求命名方案有大量的层次结构.在那个更加非正式的社区中,人们选择了一个或多或少的异想天开的项目名称并检查其他人是否已经在使用它.(在英国喜剧节目之后命名一种计算机语言可能会被认为是异想天开的.)没有人认为需要迎合一个大而缺乏想象力和笨拙的命名方案.
我们的想法是保持名称空间无冲突.而不是不可读的UUID等,反向域名不太可能以别人的方式进入.很简单,但务实.此外,当使用第三方库时,它可能会给你一个关于它们来自何处的线索(用于更新,支持等)