Python 单引号还是双引号

在 Python 中,字符串是由单引号、双引号或三引号包围的文本

在 Python 语法中,抛开三引号不谈,单引号 '' 和双引号 "" 在定义字符串这件事上有相同的权力,Python 在字符串的使用上给了用户足够的决定权,但对于编程来说,”都可以” 的不确定性就是最大的问题本身

那么回到问题:到底是使用单引号还是双引号包围字符串


事情要从 Black 说起,就是著名的 Black formatter,是一个由 Python Software Foundation 主导的开源代码格式化工具。我猜叫 Black 是因为黑色物质吸收全频段可见光,是其他各种颜色物质的总和,并且他也在官网给出了解释

Black 团队是一个非常有性格,不妥协的团队,他们甚至把这写到他们官网最上面最大的 slogan 上:”The uncompromising Python code formatter”

就在 2018 年 4 月 9 日,平平无奇的一天, 在Black 的 GitHub仓库里出现的第 118 号 issue 让它终于要面对这个在 Black有史以来最具争议的问题:

字符串应该用单引号还是双引号

不过你至少得先知道Issue 是什么

问题提出(Issue Statement)


一个 GitHub 叫做 bofm 的用户在 2018 年 4 月 9 日这一天开启了名为 Signal quotes option 的第 118 号 Issue:

Hi! Although Black now prefers doubles, can we have an option to keep single quotes? Forcing double quotes would make this great project unusable for many users who picked the rule of using single quotes.

Operating system: MacOS
Python version: 3.6
Black version: 18.4a0
Does also happen on master: yes

他希望能够提供单双引号的选项因为他手上有维护一个用单引号的很大的项目,并且要求单引号也是一个合理的诉求,字符串用单引号也是一种常用的风格(approved code style)

在开发者询问原因时他也提出了认为单引号合理的几点原因:

The reasons to add single quotes options:

  • Black is unusable when contributing to an existing project written with single quotes
  • Python official documentation uses single quotes in code examples
  • default repr() produces single-quoted string literals for most standard types (dict, list, tuple, str, bytes, namedtuple, etc)
  • many popular projects and their docs use single quotes
  • PEP proposals mostly use single quotes in code examples
  • Guido used single quotes in his latest commits on Github

Let me emphasize - the point is that restricting the quotes variants to only double quotes makes this cool project unusable for a big part of Python programmers.

严词拒绝


但是对于管理员 ambv来说,似乎这是完全不可接受的,他说这一大堆原则总结来说可以用一句话描述”涛涛者天下皆是也。因为别的项目没有原则,所以 Black 也不应该有原则”

至于罗列出来的几点原因,比如大的项目或者大佬都在使用单引号,所以就应当使用单引号。ambv指出,这是迷信/盲从权威,你这么着我们就没法谈了。对于你说 Black 强制双引号会让相当大一部分写 Python 的用不了这点不买账(I also don’t buy),为啥不能用,而且就算你双引号(的项目/用户量)很大,但是我的(态度)很硬,你们的双引号没关系,用 Black 一键变成双引号就完事了。用户 gaggle也表示你可能根本就不是 Black 的目标受众,而且本身 Black 就是让人们不用再考虑这些 Bikeshedding 的问题

也有老哥来安慰他来了,用户kalekseev 说既然你 Black 加一个单引号的选项不难而且有很多人相加你为啥不加?每一行的宽度都能选,选一个单双引号有啥难的 prittier人家就提供了单双引号的选项。不管咋说哥们他 Black 不给你加你自己 fork 一下自己做也行,从#75 这里他们那个时候还在用单引号,这就有现成的能用不是

管理员破防


可能就是这个 fork 让ambv 直接破防了,随即输出了一大堆表明观点:

  • Black 项目的核心原则之一(也是初衷)是标准化,让用户不用过多地为格式操心,所以他永远不会添加一堆宽度选项啥的(All blackened code looks the same)。选项越多,负担越大(所以不打算给用户选择的机会)
  • 选择双引号的原因是:1. 因为标准化所以只能二选一 2. 因为双引号比单引号更好所以双引号
  • 他其实不在乎到底是单引号还是双引号,过去另外两个管理员carljmzsol说服了他用双引号所以双引号
  • 也没人说出具体的论据要用单引号更好(在线等一个理由)

对于过往那些所谓”论据”都不成立,其一 Black 是一个没有历史包袱的项目,不要妄图用历史包袱(以及权威)来自我束缚,其二是在所有键盘布局上,单引号并不比双引号更容易敲。ambv重申并且重点强调没关系你们爱用单引号可以用无所谓反正 Black 可以给你一键转换

加上PS,因为项目早期声明遵循 MIT 协议,所以他也不能不让你 folk,但是有人在自己的项目Issues里面提建议他感觉有被冒犯到

感觉这最后一句话才是ambv打了这么长一段话的直接原因,一直憋到最后终于能说出来了

从这一段来看感觉他真的破防了,首先这个用双引号的理由看起来就是无理取闹,也没有人说单引号 preferable,最开始的诉求只是希望能有单引号的选项而不是只能默认单引号而已。另外,主流键盘布局上,单引号只需要按一次,而双引号都需要搭配Shift所以至少需要两次按键操作,单引号就是比双引号好打。但是ambv特意斜体强调在All keyboard layout 都不存在更容易敲的情况

在随后的两天并没有新的讨论,所以ambv认为他也没有等到自己想要的一个解释,就关闭了讨论

直面问题


不知道为什么,在ambv等一个讨论的时候,这个议题在随后的半个月几乎销声匿迹,但随后又逐渐升温,原本提出者的诉求只是增加一个可选项,让开发者可以选择字符串用单引号,但讨论和核心逐渐倾向于: 为什么单引号比双引号更好? 在讨论中也得出了不少实际佐证用单引号比双引号更优越的证据

在说为什么双引号更好之前,有一个小插曲不得不提。一位叫alanhamlett的暴躁老哥在这个 issue 中头一回质问管理员ambv:前面你说双引号更好,那双引号为啥好? ambv马上反问难道 README 里的解释还不够吗?(当年在 README里还包含有对于 Black 代码风格的描述,现在全都迁到官方文档页了)没想到老哥直接回怼:对那个解释就是不够(你说别人理由不充分那我也说你理由不充分)。你应该直接就遵守Prettier’s example 直接允许修改配置文件而不是把用单引号的大量开发团队拒之门外。这就是个鸡毛蒜皮的小问题你ambv只要开放允许设置引号偏好行了

这下肯定不能忍,ambv直接提醒他注意言辞,他这么说话很难让人接受,并且:

Calling a conversation childish because you disagree with the other side of the argument is unnecessarily escalating the situation. Accusations of “blocking massive amounts of teams” is hyperbole and unfair. Telling unpaid maintainers of an open source project what they “should” do is arrogant. You have no skin in this game and are in no position to demand any action.

因为不赞同就说别人幼稚只会空令事态升级;你指责的把大量开发人员拒之门外也离谱;你凭什么告诉我们这些用爱发电的开源项目作者”该做什么”

随后他集中做了声明:Black 严格作为 PEP 8 规范子集(an at a strict subset of PEP 8,但是 Harmon说Black的格式化规则是PEP8 的超集superset)的一次尝试(每次决策都是非常谨慎的)。使用 Black 的用户可以放心地预期到自己该自己的代码在 Blacken 后该是个什么样子。如果给在引号的问题上放开了配置文件的选项,开了这个先河之后,放开更多配置的要求将如雪片般涌来,为之奈何

在这之后又有暴躁老哥 audiolion 说确实 Python 没有一个像是 Prettier 一样 admittedly 的 formatter,Black 很好但是很可惜它执着于这个双引号,肯定会有很多人不满意。我敢保证一定会有人 folk 一个有单引号选项的 Black,这不是为了取而代之,是很难认同你的人们的无奈之举

奇怪的是,这次ambv没有对 folk 抱之前那么大的反应,大概是他被这句 “If you don’t, I guarantee someone will just fork this and add in single quotes and just merge changes from this upstream repo.” 触动到了。他不可能阻挡别人 folk 他的项目,而这次如果不能处理得到一个大部分都满意的结果,大概真的会有人 folk 一个分支添加引号可选项,可以预见到的是这个分支不会像他说的变得越来越复杂,并且会有大量的 star,如果有一天这个分支的 star 甚至要多过 main,这就是他们审美不符合多数 Python 开发者的明证

至少在五月二十六号这一天,他重开了这个 issue,这个问题才重新被当做一个问题来看待。或许在这时候他已经明白问题的严重性,只等一个台阶

观点整理


叫做 zestyping`的大佬依来源和问题分类整理了从古至今的所有观点论据(大致如下):

从来源来说

README(当时的readme)

  • 用双引号之后字符串内的单引号不用转义(可能字符串内单引号更多)
  • 在有些字体中两个单引号长得跟一个双引号一样(所以应避免单引号)
  • C 语言的字符串用双引号
  • 单引号在很多键盘上更容易打

#51

  • 单引号更容易打

  • 在有些字体中两个单引号长得跟一个双引号一样

  • C 语言的字符串用双引号

  • repr() 默认返回单引号格式(直接在 Python 解释器的终端输入变量就能看到定义,有别于 print)

  • 很多人气开源项目都默认单引号

#75

  • 在含有单引号的一堆英文字符串中强制转换为双引号更丝滑

#118

  • 有一些项目和工作环境代码风格采用单引号
  • Python 官方文档的用例采用单引号
  • repr() 采用单引号,除非字符串内包含单引号
  • PEP proposals 大多用单引号
  • Guido 倾向于在人读的字符串用双引号,否则用单引号
  • 有一些人用单双引号区分两种不同的字符串
  • 有人提出引号影响阅读(noisy),引号越少噪音越少,所以单引号比双引号噪音更少
  • 在 Sublime 里,一些代码语法高亮风格不能识别双引号
  • Kenneth Reitz 的 PEP 8 amendment 建议采用 repr() 默认的单引号的方式

Hacker News(HN)

  • Python 的官方文档倾向于使用单引号
  • Python 的标准库倾向于使用单引号
  • repr() 和用户在解释器里看到的一样(都是单引号)
  • repr() 方法已经太久了(过时了)
  • 在 sh/bash 中,单引号是针对没有可变拓展或者其他替代的字符串文字
  • Guido 人读的用双引号,其他单引号
  • 双引号看起来更乱(noisy)
  • 在常用键盘布局上双引号要按键盘两次
  • 英文散文(English prose)一般用双引号引用,在其中用单引号
  • 单引号包裹的字符串可以直接包含有双引号的句子

随后他又把观点按类别进行了整理。随后ambv就来 say hi,原来是因为这位 zestyping 曾经对项目有过贡献,Black 有使用过他写的 lib2to3,但是紧随其后也对他总结的逐条写原因反驳(集中回复):

Python 官方文档和标准库更倾向于使用单引号

错误的,虽然单引号更多一些但是他们俩没有倾向没有推荐,更不要说有什么准则了。我很确定大部分开发者不在乎单引号还是双引号他们就只是随便用的。所以(在这个先验知识下),统计单双引号的比例也没啥意义(估计是五五开)

Guido 倾向于使用单引号

也是错误的,我和他就这个事情聊过所以我知道,他说人一般读的字符啥的用双引号,然后数据什么的用单引号

双引号在Sublime Text里影响的代码高亮

很可悲这是 sublime 的问题他们应该要修 bug,这不该是你倾向使用单引号的理由。 jhirardet提到他用 MagicPython 替代 Sublime 自己的代码高亮所以还真没注意到这点

双引号比单引号更 noisy

如果说双引号真的更 noisy 的话为啥 English prose(英文散文?)还要用双引号,而且双引号作为视觉(看到内容)的区分要早于单引号。就算 noisy 这个 noise 的程度又要怎么去衡量,这个标准能量化吗,就算能,差异肯定也小到忽略不计,相当于我们就也能说 M 比 N 更 noisy,而 ‘,’ 逗号又比 ‘.’ 句号更 noisy

这时用户 kadrach 发表了一个有意思的评论:

他总结了在 pypi 上下载次数最多一百个包,分析了其中的 .py 文件中单双引号分别出现的次数,并且计算了单引号出现的比重和包的数量之间的关系,横轴是比重,纵轴代表数量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Density plot of quote bias in top100 packages.
Bias calculated as num_single/(num_single+num_double)
++----------+----------+----------+-----------+----------+-+
| ********** |
| ** ** |
| *** ** |
1.5 + ** ** +
| ** ** |
| ** * |
| ** * |
1 + ** ** +
| ** ** |
| *** ** |
| ****** ** ** |
0.5 + **** ***** ***** *** +
| * *** ** |
++----------+----------+----------+-----------+----------+-+
0 0.2 0.4 0.6 0.8 1

随后他们讨论了这个方法的严谨性,包括考虑用 1000 个包而不只是前 100 个;是不是要排除掉注释部分的内容;是否/怎么排除互相调用(抄)的部分, ambv 建议考虑 AST(好像是抽象语法树)

语法树是一种将源代码转化为树形结构的数据结构,用于展示代码的结构和层次。

它帮助程序员理解代码结构,并且是进行代码解析、优化和转换的基础。

具体含义

  • 解析树(Parse Tree):直接从源代码解析得到的树状结构,包含了所有语法信息。
  • 抽象语法树(Abstract Syntax Tree, AST):对解析树进行简化和浓缩后的版本,只保留与代码分析相关的部分,忽略一些无关紧要的信息如分号或逗号等。

可以猜测在讨论的过程中 ambv的态度逐渐软化并且直到一个叫做kbd的用户来做总结性发言:很多人都用不同的引号来代表不同的含义,单引号用于代码,数据;双引号用于文档,人类可读内容,这是有很多人不同意强制转换双引号的根源

大概是这样:

1
['my_key'] = "my string"

instead of

1
["my_key"] = "my string"

从一些尝试我们可以看到 Python 对于单引号的偏爱:

1
2
3
4
5
6
7
8
9
10
11
12
13
>>>> a = 'abc\'def"ghi'
>>>> b = "abc'def\"ghi"
>>>> c = 'abc\'def\"ghi'
>>>> d = "abc\'def\"ghi"

>>>> a
'abc\'def"ghi'
>>>> b
'abc\'def"ghi'
>>>> c
'abc\'def"ghi'
>>>> d
'abc\'def"ghi'

最终妥协


随后ambv表示赞同,不久后 Black 发布 18.6b0 版本,提供了 – –skip-string-normalization 选项,可以简称为为 -S 以允许 Black 不强制统一双引号。

不过 Black 仍然默认并且强烈建议将所有引号强制为双引号因为 Black 的偏好代码风格仍然没有改变,仍然认为默认双引号是更好的选择

希望这个选项能够让所有人满意,这是 Black 历史上最有争议的话题

I hope this resolves to your satisfaction what’s been the most controversial issue in Black’s history.

END:)

bikeshedding(Law of triviality)


Law of Triviality,又叫 Parkinson’s Law of Triviality 帕金森凡俗法则、帕金森琐碎定理、鸡毛蒜皮定律、芝麻绿豆定律,由英国一个人叫帕金森于 1957 年提出,用来描述大型组织会花费大量时间在讨论无关紧要的琐事,但是真正重大的决议反而可以轻松过关的现象。这是由于人对大议题较难有全面性的理解,所以怕贸然提出异议,可能会失言;相反地,对于一些简单琐碎的小事,有相当的认识,因此意见特别多,呈现出组织在各事项上讨论所花费的时间,通常与事项本身的重要程度呈现反比的情况。

他在自己的著作中首次提出这个理论,并描述了一个虚构的事件:

一个虚构的财政议会中讨论的三项议题:第一项为搭建价值一千万英镑的反应堆,第二项为价值 350 英镑的员工自行车棚,第三项为每年 21 英镑联合福利议会茶店的提案。

  1. 一千万英镑的核反应堆在数额和技术含量上都高高在上遥不可及,在两分半的讨论之后便通过了。一名议会成员提出了完全不同的计划,然而无人愿意放弃议会取得的进展而响应寥寥,另一位熟稔该议题的成员略有担忧,然而他觉得无法向议会的其他成员解释清楚,最终作罢。
  2. 自行车棚的议题则处于所有人理解范围之内,并有丰富人生经验予以支撑意见,议会成员 Softleigh 先生表示铝制棚顶价格高昂,应使用石棉。Holdfast 先生提议使用镀锌铁,Daring 先生则对自行车棚是否必要表示质疑。 Holdfast 表示反对。在经过 45 分钟的讨论,并得出有可能节省 50 英镑的结果之后,议会成员带着完成使命的成就感纷纷坐回原位。
  3. 帕金森继续描写第三项议题:“也许有些成员无法区分铝制棚顶或石棉棚顶,但是所有人都了解咖啡-它是什么,应该如何做,该在哪买-以及到底该不该买。这项议题将会占用议会成员一小时加一刻的时间,然而由于时间关系,会议结束时议员要求会议秘书提供更多信息,同时将此项议题的决定留待下次议会处理。”

Python 单引号还是双引号
http://pafl.top/2024/11/18/Python-单引号还是双引号/
Author
Paf
Posted on
November 18, 2024
Licensed under