你能解释一下Python基础库中函数命名的奇怪和不一致性吗?

10
当我开始学习Python时,我爱上了它的结构化程度,比起具有许多不太易于理解的函数的PHP而言,但是我也注意到在Python中存在着一些奇怪的不一致性,没有明显的合理性依据。
例如,在PHP中,有一些数组函数的名称以"array"开头,有些则没有,有些使用下划线,有些将名称的某些部分缩短为单个字符等等,它们通常需要将一个数组作为参数,而不是数组对象的方法。
在Python中,有很多单词函数名,但涉及到多个单词时,我看到了不一致性。例如,logging模块的方法使用驼峰命名法,如logging.StreamHandler(),sys中使用下划线,如sys.base_prefix(),而os中则直接使用小写字母而没有分隔符,如os.expandvars()。如果这还不够,就会出现像os.path.splitext()这样的函数名,最终导致我发布了这篇文章。
为什么它们不都遵循同一种约定呢?
logging.StreamHandler() # capitalize in case classes
sys.basePrefix()
os.expandVars()
os.path.splitText()

甚至可以像这样:
logging.stream_handler()
sys.base_prefix()
os.expand_vars()
os.path.split_text() # the original is actually "spli + text" in one word!

是否存在任何流行的编程语言严格遵守类似于以下示例中的约定?

some_value        # variable lower case separated by underscores (which allows them to appear descriptive)
someFunction()    # functions and methods camel case, first letter lower case (differentiates from variables while still readable and allows simple names like get() and send())
SomeObject()      # classes always start with capital letters and are camelcase (makes them stand out and above but appear closer to functions)
IMPORTANT_VALUE   # constants always upper case, separated by underscores (easily tell apart from anything else, while being the reverse case from normal variables)

那么为什么会发生这种情况?类似于我的例子,在现实中是否经常发生这种情况?

1
在Pandas中,tolist()真的让我很烦恼,因为其他所有东西都是to_csv()等(尽管不是基本库)。现在我已经抱怨过了,因为人类是不一致的,这也许就是“为什么会发生这种情况”的答案。 - roganjosh
在我看来,如果您决定在模块中采用一种约定,但后来又决定省略某些英语单词的字母,有时甚至完全不遵循任何约定,只是以某种方式将单词混合在一起,那就有点过了...否则,我会相信这确实是人类漂浮在自己的一致性周围的典型特征。 - a_rts
2
好的,Python 中应该始终遵循 PEP8 规范。然而,由于它应用不一致性,来自成百上千人的大量工作中存在着不一致性。我仍然不知道什么样的回答能够使您满意;这是由于人们的不一致造成的。 - roganjosh
1
PEP8也解决了这个问题;通常是“因为历史”,而不是“因为人们”。请参见“愚蠢的一致性是小心灵的妖怪”一节。话虽如此,这个问题实际上无法给出技术答案。答案是“因为它们就是这样”。同样的原因,牛的复数形式是oxen,而不是oxes。(至于一个“流行”的编程语言严格遵守所给出的规则,即PEP8规则,没有。) - Rob Napier
1
splitext不是split text的奇怪缩写,而是split ext(分割扩展名)的缩写,所以这是有意义的。否则,我完全同意Python中存在命名不一致的问题。 - domsson
@roganjosh 我也觉得很烦,显然这是“为了与numpy兼容,例如numpy.tolist是标准方法”https://github.com/pandas-dev/pandas/issues/8826#issuecomment-63182100自0.24.0版本以来,可以使用.to_list()别名 https://pandas.pydata.org/pandas-docs/stable/whatsnew/v0.24.0.html。 - Jonáš Jančařík
2个回答

0

这些不一致性的部分原因是因为Python开发人员认为单个模块内的一致性比与标准库其余部分的一致性更重要。

至于为什么标准库中的模块具有不同的命名约定,其中许多是由于许多原因而产生的。例如,os模块中的大多数函数都是C标准和系统/POSIX库中具有相同名称的函数的简单包装器;为了减少C和Python开发人员之间的摩擦,并利用开发人员对POSIX的现有知识,C名称已经被直接用于该模块。在os模块中有一些函数没有与C / POSIX函数对应,但为了避免os模块内部不一致性,它们也继承了C命名约定。

如果您想要更Pythonic版本的标准库,则可以使用许多os函数的高级封装,例如subprocess模块和pathlib。这些模块遵循PEP8命名约定。

PEP8规定类名使用CamelCase,变量、函数和属性名使用snake_case,这解释了logging.StreamHandlersys.base_prefix之间的区别。

对于像XML/HTML DOM这样的库,它们指定的函数名称更符合JavaScript命名约定(XML和HTML DOM API是由Web标准人员设计的,遵循JavaScript的传统),或者比如unittest,它是基于Java的xUnit设计的。Python决定采用这些现有的命名约定,以利用那些已经熟悉这些名称的人的熟悉度,因为API被简单地原样复制。

然后就决定在英文单词中偶尔省略一个字母

大多数省略字母的函数名称通常来自古老的C库,当时文本编辑器还不太先进,人们想要节省字母以缩短变量名的输入长度,或者当你能使用的字符数量有限制时。Python和PHP继承了许多这些名称,用于这些函数的低级封装。

Python常被用作粘合语言,这意味着它经常用于从其他语言编写的库中组装应用程序,这些库具有自己现有的命名约定。为了符合Python的命名约定而重新命名这些已建立的接口只会毫无理由地混淆那些熟悉已建立API的人们,因为在阅读文档时与已建立API的一致性更重要,在与标准库的其余部分保持一致性方面则几乎只是为了美感。


-4

这是一个很好的问题。我相信这是因为人们可以为它们命名,所以对于一些人来说,效率胜过可读性;而对于其他人来说,则正相反。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接