花下貓語:Python 中下劃線的用法令人歎為觀止,相信你已在各種文章或教程中見識過了。在 2016 年的 3.6 版本之後,Python 還引入了一種新的語法,使得下劃線也可以出現在數值中。這篇翻譯的文件,將帶你重溫這個特性的引入過程。
PEP原文:https://www.python.org/dev/peps/pep-0515
PEP標題:PEP 515 -- Underscores in Numeric Literals
PEP作者:Guido van Rossum, Nick Coghlan
建立日期:Georg Brandl, Serhiy Storchaka
合入版本:3.6
譯者:豌豆花下貓@Python貓
PEP翻譯計劃:https://github.com/chinesehuazhou/peps-cn
概要和原理
本 PEP 提議擴充套件 Python 的語法,使得在“字串變成數”(number-from-string)構造器中,下劃線可以作為視覺分隔符,對整數、浮點和複數字面量的數字進行分組。
(Python貓注:關於 Python 的數值型別,可以檢視 PEP-3141)
這是其它現代語言的一個常見特性,有助於理解長的或者值應該被直觀地分成幾部分的字面量,如十六進位制表示法中的位元組或單詞。
例子:
# grouping decimal numbers by thousands
amount = 10_000_000.0
# grouping hexadecimal addresses by words
addr = 0xCAFE_F00D
# grouping bits into nibbles in a binary literal
flags = 0b_0011_1111_0100_1110
# same, for string conversions
flags = int('0b_1111_0000', 2)
規範
目前的提議是在數字之間和在數字字面量的基本識別符號之後,允許有一個下劃線。下劃線沒有語義上的意義,數字字面量會被解析得就像沒有下劃線一樣。
字面量語法
因此,整型字面量的表示法看起來像這樣:
integer: decinteger | bininteger | octinteger | hexinteger
decinteger: nonzerodigit (["_"] digit)* | "0" (["_"] "0")*
bininteger: "0" ("b" | "B") (["_"] bindigit)+
octinteger: "0" ("o" | "O") (["_"] octdigit)+
hexinteger: "0" ("x" | "X") (["_"] hexdigit)+
nonzerodigit: "1"..."9"
digit: "0"..."9"
bindigit: "0" | "1"
octdigit: "0"..."7"
hexdigit: digit | "a"..."f" | "A"..."F"
浮點數和複數的字面量:
floatnumber: pointfloat | exponentfloat
pointfloat: [digitpart] fraction | digitpart "."
exponentfloat: (digitpart | pointfloat) exponent
digitpart: digit (["_"] digit)*
fraction: "." digitpart
exponent: ("e" | "E") ["+" | "-"] digitpart
imagnumber: (floatnumber | digitpart) ("j" | "J")
建構函式
遵循相同的放置規則,下劃線可以在以下建構函式中使用:
- int()(任意進位制)
- float()
- complex()
- Decimal()
進一步的變更
新式的數字轉字串(number-to-string)格式化語法將被擴充套件,允許 _ 作為千位分隔符。這可以用更具可讀性的字面量來輕鬆地生成程式碼。[11]
The syntax would be the same as for the comma, e.g. {:10_} for a width of 10 with _ separator.(這句沒看懂...不譯)
對於 b、x 和 o 格式符,_ 也將支援,並按 4 位數分組。
現有的技術
那些允許下劃線分組的語言,實現了大量放置下劃線的規則。在語言規範與實際行為相矛盾的情況下,以下會列出實際的行為。(“單個”或“多個”指的是允許多少連續的下劃線。)
- Ada:單個,僅在數字間 [8]
- C# (7.0 版本的提案):多個,僅在數字間 [6]
- C++14:單個,在數字之間(選了其它分隔符) [1]
- D:多個,任意位置,包括末尾 [2]
- Java:多個,僅在數字間 [7]
- Julia:單個,僅在數字間(但不含浮點指數部分) [9]
- Perl 5:多個,基本是任意位置,儘管文件說數字間限制 1 個下劃線 [3]
- Ruby:單個,僅在數字間(儘管文件說“任意位置”)[10]
- Rust:多個,任意位置,除了指數“e”與數字間 [4]
- Swift:多個,數字之間和末尾(儘管文件說僅在“數字之間”) [5]
被否決的語法
(Python貓注:每個 PEP 在初提出階段,都可能引起很多關於語法設計的討論,在正式採納的 PEP 中,一般會保留一些有代表性的被否決的方案,例如下面的兩項)
1、下劃線的放置規則
減少下劃線的使用限制,而不是上面宣告的相對嚴格的規則。在其它語言中,常見的規則包括:
- 只允許一個連續的下劃線,並且只能在數字之間。
- 允許多個連續的下劃線,但只能在數字之間。
- 允許多個連續的下劃線,在大多數位置,除了字面量的開頭,或特殊的位置(例如小數點後)。
本 PEP 中的語法最終被選中,因為它涵蓋了常見的用例,並且不會出現被 Python 風格指南所不鼓勵使用的語法。
一個不太常見的規則是隻允許每 N 位數字有下劃線(其中 N 可能是 3 個十進位制字面量,或 4 個十六進位制字面量)。這是不必要的限制,特別是考慮到這些分隔符位置在不同的文化中是不同的。(Python貓注:例如,我們國家習慣將 4 個數字分為一組,即 10000 是 1 萬,而不是英語文化中的 10 thousand)
2、其它的分隔符
還有一種建議是使用空格進行分組。雖然字串是一種結合相鄰字面量的先例,但這種行為可能會導致意外的效果,而下劃線則不會。而且,除了那些基本會忽略任何空格的語言外,沒有其它語言使用此規則。
c++ 14 引入了單引號來進行分組(因為下劃線會與使用者定義的字面量產生歧義),由於單引號已經被 Python 的字串字面量使用了,所以沒有考慮它。[1]
實現
實現上述規範的初步補丁已經發布到問題跟蹤器。[12]
參考內容
[1] (1, 2) http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3499.html
[2] https://dlang.org/spec/lex.html#integerliteral
[3] https://perldoc.perl.org/perldata#Scalar-value-constructors
[4] https://web.archive.org/web/20160304121349/http://doc.rust-lang.org/reference.html#integer-literals
[5] https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html
[6] https://github.com/dotnet/roslyn/issues/216
[7] https://docs.oracle.com/javase/7/docs/technotes/guides/language/underscores-literals.html
[8] http://archive.adaic.com/standards/83lrm/html/lrm-02-04.html#2.4
[10] https://ruby-doc.org/core-2.3.0/doc/syntax/literals_rdoc.html#label-Numbers
[11] https://mail.python.org/pipermail/python-dev/2016-February/143283.html
[12] http://bugs.python.org/issue26331
版權
該文件已放入公共領域。