6
votes

Codage par défaut des messages d'exception

Le code suivant examine le comportement de la méthode float () code> lors d'une édition d'un symbole non ASCII:

import sys

try:
  float(u'\xbd')
except ValueError as e:
  print sys.getdefaultencoding() # in my system, this is 'ascii'
  print e[0].decode('latin-1') # u'invalid literal for float(): ' followed by the 1/2 (one half) character
  print unicode(e[0]) # raises "UnicodeDecodeError: 'ascii' codec can't decode byte 0xbd in position 29: ordinal not in range(128)"


0 commentaires

4 Réponses :


2
votes

Le codage ASCII n'inclut que les octets avec des valeurs <= 127 . La gamme de caractères représentés par ces octets est identique dans la plupart des codages; En d'autres termes, "A" est chr (65) en ASCII, en latin-1, dans UTF-8, etc.

Le seul symbole, cependant, ne fait pas partie de Le jeu de caractères ASCII, donc lorsque Python tente de coder ce symbole en ASCII, il ne peut rien faire mais échouer.

Voici ce qui se passe (je suppose que nous parlons de cpython ):

float (u '\ xbd') mène à pyflat_fromstring dans FloatObject.c être appelé. Cette fonction, donnant un objet Unicode, à tour d'appel pyunicode_encodedecimal dans UnicodeObject.c appelé. D'écrémer sur le code, je comprends que cette fonction transforme l'objet Unicode en une chaîne en remplaçant tous les caractères avec un codePoint d'unicode <256 avec l'octet de cette valeur, c'est-à-dire le personnage d'un demi-caractère, ayant Le codePoint 189 est transformé en chr (89) .

alors, pyfloat_fromstring est-ce que son travail est d'habitude. En ce moment, cela fonctionne avec une chaîne ordinaire, qui contenant un octet de plage non-ASCII. Cela ne se soucie pas de cela; Il trouve juste un octet qui n'est pas un chiffre, une période ou similaire, il augmente l'erreur de valeur.

L'argument à cette exception est une chaîne xxx

C'est bien; Un message d'exception est, après tout, une chaîne. Ce n'est que lorsque vous essayez de décoder cette chaîne, à l'aide de l'encodage par défaut ASCII, que cela transforme un problème.


2 commentaires

Cela ne répond pas à ma question, j'ai peur. J'ai légèrement édité le texte original pour être plus clair. (J'ai changé la question en gras). Je crois comprendre que ASCII ne peut pas offrir une représentation pour le caractère étrange. Mon problème est que E [0] semble être codé en latin-1, même si ASCII est le codage par défaut. Mon raisonnement est que le flotteur () aurait dû soulever une exception codée par ASCII (ou unicode). Cependant, c'est en latin-1 ou quelque chose de similaire à la place. Il aurait dû tenter de coder le message d'erreur en ASCII et a échoué, élever une UnicodeDecodeError en premier lieu, pas une ValueError.


Cela aurait dû être chr (189) je suppose



0
votes

D'expérimenter avec votre code de code, il semblerait que j'ai le même comportement sur ma plate-forme (PY2.6 sur OS X 10.5).

Puisque vous avez établi que E [0] est codé avec latin-1 , le moyen correct de la convertir unicode est pour faire .decode ('latin -1 ') et pas unicode (e [0]) .

update: il semble donc que E [0] n'a pas de codage valide. Définitivement pas latin-1 . À cause de cela, comme mentionné ailleurs dans les commentaires, vous devrez appeler REC (E [0]) Si vous devez afficher ce message d'erreur avec une exception en cascade.


1 commentaires

Ce n'est pas codé comme latin-1, il suffit de convertir des valeurs ordinales unicode aux octets.



9
votes

e [0] n'est pas codé avec latin-1; Il arrive tellement que l'octet \ xbd, lorsqu'il est décodé comme latin-1, est le caractère U + 00bd.

La conversion se produit dans Objets / floatobject.c

Premièrement, la chaîne Unicode doit être convertie en une chaîne d'octets. Ceci est effectué en utilisant pyunicode_encodedecimal () : xxx

qui est implémenté dans UnicdeObject.c . Il n'effectue aucune sorte de conversion de jeu de caractères, il écrit juste des octets avec des valeurs égales aux ordinaux unicode de la chaîne. Dans ce cas, U + 00bd -> 0xbd.

Le formatage de l'instruction La mise en forme de l'erreur est la suivante: xxx

s contient la chaîne d'octets créée plus tôt. pyos_snprintf () écrit une chaîne d'octets et s est une chaîne d'octets, il suffit donc de l'inclure directement.


2 commentaires

Devrait-il être considéré comme un bug en python? Mon raisonnement: si float () a reçu une chaîne unicode, elle devrait lancer une exception décrite unicode si le message va inclure l'entrée. Sinon, des exceptions ne peuvent pas être traitées en toute sécurité, comme l'exemple de l'exemple.


Je pense que l'appeler un bug est juste - l'erreur Messaeg devrait probablement contenir REC (V) au lieu de STR (s) , car connaissez la valeur d'entrée d'origine est plus utile. que la version codée décimale.



5
votes

Très bonne question!

J'ai pris la liberté de creuser dans le code source de Python, qui est une simple commande sur la configuration correcte des distributions Linux ( apt-get source python2.5 ) < / p>

sacrément , John Millikin m'a battu. C'est vrai, pyunicode_encodedecimal est la réponse qu'il l'est ici ici: xxx

voir, il laisse tous les points de code UNICODE <256 en place, qui sont les Les caractères latin-1, basés sur la compatibilité en arrière d'Unicode.


addendum

Avec cela en place, vous pouvez vérifier en essayant d'autres caractères non latins-1, il va lancer Exception différente: xxx


0 commentaires