Чому Python 3 дозволяє "00" як буквальний для 0, але не дозволяє "01" як буквальний для 1?


111

Чому Python 3 дозволяє "00" як буквальний для 0, але не дозволяє "01" як буквальний для 1? Чи є вагомі причини? Ця непослідовність мене бентежить. (І ми говоримо про Python 3, який навмисно порушив зворотну сумісність для досягнення таких цілей, як послідовність.)

Наприклад:

>>> from datetime import time
>>> time(16, 00)
datetime.time(16, 0)
>>> time(16, 01)
  File "<stdin>", line 1
    time(16, 01)
              ^
SyntaxError: invalid token
>>>

42
Зараз його неможливо видалити, або це порушить зворотну сумісність із цим питанням!
Джон Ла Рой

Відповіді:


103

На https://docs.python.org/3/reference/lexical_analysis.html#integer-literals :

Цілі літерали описуються такими лексичними означеннями:

integer        ::=  decimalinteger | octinteger | hexinteger | bininteger
decimalinteger ::=  nonzerodigit digit* | "0"+
nonzerodigit   ::=  "1"..."9"
digit          ::=  "0"..."9"
octinteger     ::=  "0" ("o" | "O") octdigit+
hexinteger     ::=  "0" ("x" | "X") hexdigit+
bininteger     ::=  "0" ("b" | "B") bindigit+
octdigit       ::=  "0"..."7"
hexdigit       ::=  digit | "a"..."f" | "A"..."F"
bindigit       ::=  "0" | "1"

Немає обмеження для довжини цілих букв, крім того, що може зберігатися у доступній пам'яті.

Зверніть увагу, що провідні нулі в ненульовому десятковому числі не допускаються. Це для розбіжностей з восьми буквальними буквами у стилі С, які Python використовував до версії 3.0.

Як зазначалося тут, провідні нулі в ненульовому десятковому числі не допускаються. "0"+є юридичним як дуже особливий випадок, якого не було в Python 2 :

integer        ::=  decimalinteger | octinteger | hexinteger | bininteger
decimalinteger ::=  nonzerodigit digit* | "0"
octinteger     ::=  "0" ("o" | "O") octdigit+ | "0" octdigit+

SVN-комітет r55866 реалізував PEP 3127 в токенізаторі, який забороняє старі 0<octal>числа. Однак цікаво, що він також додає цю примітку:

/* in any case, allow '0' as a literal */

зі спеціальним nonzeroпрапором, який викидає лише a, SyntaxErrorякщо наступна послідовність цифр містить ненульову цифру.

Це дивно, тому що PEP 3127 не дозволяє цей випадок:

Цей PEP пропонує, щоб можливість вказувати восьмеричне число за допомогою провідного нуля буде видалено з мови в Python 3.0 (і в режимі попереднього перегляду Python 3.0 2.6), і що SyntaxError буде підніматися щоразу, коли ведучим "0" буде одразу слідує ще одна цифра .

(наголос мій)

Отже, той факт, що дозволено кілька нулів, технічно порушує ПЕП, і в основному був реалізований як особливий випадок Георга Брандла. Він вніс відповідну зміну документації, щоб відзначити, що це "0"+було дійсною справою decimalinteger(раніше це стосувалося octinteger).

Ми, мабуть, ніколи точно не дізнаємось , чому Георг вирішив зробити "0"+дійсним - це може назавжди залишитися випадковим кутовим випадком у Python.


ОНОВЛЕННЯ [28 липня 2015]: Це питання призвело до бурхливої ​​дискусійної теми про ідеї пітона, на яку Георг звучав :

Стівен Д'Апрано написав:

Чому це було визначено саме так? [...] Чому б ми писали 0000, щоб отримати нуль?

Я міг би сказати тобі, але тоді я мав би тебе вбити.

Георг

Пізніше нитка породила цей звіт про помилку, спрямований на те, щоб позбутися цього особливого випадку. Ось Георг каже :

Я не пригадую причину цієї навмисної зміни (як видно із змін у документах).

Зараз я не можу придумати вагомих причин для цієї зміни [...]

і таким чином ми маємо це: точна причина цієї суперечливості втрачається в часі.

Нарешті, зауважте, що звіт про помилку було відхилено: провідні нулі й надалі прийматимуться лише за нульовими цілими числами для решти Python 3.x.


6
Чому ти кажеш "Ми, мабуть, ніколи точно не дізнаємось, чому Георг вирішив ..."? Якщо хтось, хто його знає, бачить цю нитку і повідомляє про це, то він може прийти, щоб дати свою відповідь! (якщо ви не знаєте, що він назавжди відмовляється обговорювати свою минулу роботу Python чи якусь подібну обставину)
морж

1
Я не розумію, чому вони не просто склали другий octintegerвипадок Python 2 "0" octdigit*. 0є восьмеричним буквалом в C / C ++.
Випадково832

1
Насправді англійська мова є дещо неоднозначною у цьому плані. Слово "інший" може означати "ще один" або може означати "інший". Одне правильне тлумачення англійською мовою жирної цитати з PEP 3127 означає: "Синтаксичний помилка буде підніматися щоразу, коли за ведучим" 0 "одразу слідує цифра, відмінна від" 0 "" Я не впевнений, чи справді це було призначено ( хоча ця інтерпретація, мабуть, підкріплена фактичним кодом), але в будь-якому випадку, я не думаю, що це точно сказати, що PEP технічно порушений без додаткового уточнення цього речення.
GrandOpener

2
@GrandOpener: Зауважте, що 001це незаконно, тоді як ваше тлумачення зробить це законним (оскільки значення "негайно" повинно бути досить однозначним).
nneonneo

Гарна думка. Отже, PEP безумовно порушується; що неоднозначно, точна природа, в якій вона порушується. :)
GrandOpener

17

Це особливий випадок ( "0"+)

2.4.4. Цілі літерали

Цілі літерали описуються такими лексичними означеннями:

integer :: = десятковий цілий | octinteger | hexinteger | дворядник
десятковий знак :: = нерозуміна цифра * | "0" +
nonzerodigit :: = "1" ... "9"
цифра :: = "0" ... "9"
octinteger :: = "0" ("o" | "O") octdigit +
hexinteger :: = "0" ("x" | "X") hexdigit +
bininteger :: = "0" ("b" | "B") bindigit +
octdigit :: = "0" ... "7"
hexdigit :: = цифра | "a" ... "f" | "А" ... "F"
bindigit :: = "0" | "1"

Якщо ви подивитеся на граматику, легко зрозуміти, що 0потрібна спеціальна справа. Я не впевнений, чому ' +' вважається необхідним там. Час перекопатися у списку розсилки розробників ...


Цікаво зауважити, що в Python2 більше одного розбирали 0як octinteger(кінцевий результат все-таки є 0)

десятковий знак :: = нерозуміна цифра * | "0"
octinteger :: = "0" ("o" | "O") octdigit + | Octdigit + "0" +

1
І будь-яка ідея, чому існує "0"+і ні "0"?
лейлот

1
@lejlot, ще не - але я заінтригований. Це, безумовно, частина специфікації
Джон Ла Рой

3

Python2 використовував головний нуль для визначення восьмеричних чисел:

>>> 010
8

Щоб уникнути цього (? Вводять в оману) поведінка, Python3 вимагає явних префіксів 0b, 0o, 0x:

>>> 0o10
8

15
Залишається питання: чому це 00дозволено? (І 000, 0000тощо)
Майкл Гірі

4
@MichaelGeary: можливо, тому, що це не може бути неоднозначним (00000000 - це 0, незалежно від бази), і видалення його буде непотрібно порушувати код? Ще дивно.
RemcoGerlich

5
@RemcoGerlich Якщо я не помиляюся, 01також 1незалежно від бази.
Холт

2
@Holt: але дозволяти "0" + "1"? як особливий випадок, мабуть, буде ще більш заплутаним.
RemcoGerlich

4
@RemcoGerlich Ніколи не говорив, що це не буде;) Я просто говорив, що can't be ambiguousце не аргумент, оскільки теж 01не може бути неоднозначним. ІМО, 00справа - це лише особливий випадок, тому що саме такого не 0повинно бути.
Холт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.