web-dev-qa-db-fra.com

Pourquoi Python 3 autorise "00" comme littéral pour 0 mais pas "01" comme littéral pour 1?

Pourquoi Python 3 autorise "00" comme littéral pour 0 mais pas "01" comme littéral pour 1? Y a-t-il une bonne raison? Cette incohérence me déconcerte. (Et nous sommes parler de Python 3, qui a délibérément rompu la compatibilité descendante afin d'atteindre des objectifs tels que la cohérence.)

Par exemple:

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

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

Les littéraux entiers sont décrits par les définitions lexicales suivantes:

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"

Il n'y a pas de limite pour la longueur des littéraux entiers en dehors de ce qui peut être stocké dans la mémoire disponible.

Notez que les zéros non significatifs dans un nombre décimal non nul ne sont pas autorisés. C'est pour la désambiguïsation avec des littéraux octaux de style C, qui Python utilisé avant la version 3.0.

Comme indiqué ici, les zéros non significatifs dans un différent de zéro nombre décimal ne sont pas autorisés. "0"+ est légal comme un cas très spécial, qui n'était pas présent dans Python 2 :

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

SVN commit r55866 implémenté PEP 3127 dans le tokenizer, ce qui interdit l'ancien 0<octal> Nombres. Cependant, curieusement, il ajoute également cette note:

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

avec un indicateur spécial nonzero qui ne lance un SyntaxError que si la séquence de chiffres suivante contient un chiffre différent de zéro.

C'est étrange car PEP 3127 ne permet pas ce cas:

Ce PEP propose que la possibilité de spécifier un nombre octal en utilisant un zéro de tête sera supprimée de la langue en Python 3.0 (et le mode de prévisualisation Python 3.0) de 2.6), et que une SyntaxError sera levée chaque fois qu'un "0" de tête est immédiatement suivi d'un autre chiffre .

(c'est moi qui souligne)

Donc, le fait que plusieurs zéros soient autorisés est techniquement violant le PEP, et a été fondamentalement implémenté comme un cas spécial par Georg Brandl. Il a apporté la modification de documentation correspondante pour noter que "0"+ était un cas valide pour decimalinteger (précédemment couvert par octinteger).

Nous ne saurons probablement jamais exactement pourquoi Georg a choisi de faire "0"+ valide - il peut toujours rester un cas de coin étrange en Python.


[~ # ~] mise à jour [~ # ~] [28 juillet 2015]: Cette question a conduit à un fil de discussion animé sur les idées de python dans lesquelles Georg a sonné dans :

Steven D'Aprano a écrit:

Pourquoi a-t-il été défini de cette façon? [...] Pourquoi écririons-nous 0000 pour obtenir zéro?

Je pourrais te le dire, mais il faudrait que je te tue.

Georg

Plus tard, le fil a engendré ce rapport de bogue visant à se débarrasser de ce cas spécial. Ici, Georg dit :

Je ne me souviens pas de la raison de ce changement délibéré (comme le montre le changement de documentation).

Je ne suis pas en mesure de trouver une bonne raison pour ce changement maintenant [...]

et ainsi nous l'avons: la raison précise derrière cette incohérence est perdue avec le temps.

Enfin, notez que le rapport de bogue a été rejeté: les zéros de tête continueront d'être acceptés uniquement sur zéro entier pour le reste de Python 3.x.

100
nneonneo

C'est un cas particulier ("0"+)

2.4.4. Littéraux entiers

 Les littéraux entiers sont décrits par les définitions lexicales suivantes: 
 
 Entier :: = nombre décimal | octinteger | hexinteger | bininteger 
 decimalinteger :: = chiffre nonzerodigit * | "0" + 
 Nonzerodigit :: = "1" ... "9" 
 Chiffre :: = "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"

Si vous regardez la grammaire, il est facile de voir que 0 besoin d'un cas spécial. Je ne sais pas pourquoi le '+ 'est cependant considéré comme nécessaire. Il est temps de fouiller dans la liste de diffusion des développeurs ...


Il est intéressant de noter qu'en Python2, plusieurs 0 a été analysé en tant que octinteger (le résultat final est toujours 0 bien que)

 nombre décimal :: = chiffre non azérodigit * | "0" 
 Octinte ::: "0" ("o" | "O") octdigit + | Octdigit "0" + 
17
John La Rooy

Python2 a utilisé le zéro de tête pour spécifier les nombres octaux:

>>> 010
8

Pour éviter ce comportement (trompeur?), Python3 requiert des préfixes explicites 0b, 0o, 0x:

>>> 0o10
8
4
dlask