71 votes

Pourquoi la taille de cette chaîne Python change-t-elle en cas d'échec de la conversion int?

Du tweet ici :

 import sys
x = 'ñ'
print(sys.getsizeof(x))
int(x) #throws an error
print(sys.getsizeof(x))
 

Nous obtenons 74, puis 77 octets pour les deux appels getsizeof .

Il semble que nous ajoutions 3 octets à l'objet, à partir de l'appel int ayant échoué.

Quelques exemples supplémentaires tirés de Twitter (vous devrez peut-être redémarrer python pour rétablir la taille à 74):

 x = 'ñ'
y = 'ñ'
int(x)
print(sys.getsizeof(y))
 

77!

 print(sys.getsizeof('ñ'))
int('ñ')
print(sys.getsizeof('ñ'))
 

74, puis 77.

71voto

user2357112 Points 37737

Le code qui convertit les chaînes à ints dans Disponible 3.6 demandes UTF-8 formulaire de la chaîne de travailler avec:

buffer = PyUnicode_AsUTF8AndSize(asciidig, &buflen);

et la chaîne crée l'UTF-8 est la représentation la première fois qu'il est demandé et il la met en cache sur l'objet de type string:

if (PyUnicode_UTF8(unicode) == NULL) {
    assert(!PyUnicode_IS_COMPACT_ASCII(unicode));
    bytes = _PyUnicode_AsUTF8String(unicode, NULL);
    if (bytes == NULL)
        return NULL;
    _PyUnicode_UTF8(unicode) = PyObject_MALLOC(PyBytes_GET_SIZE(bytes) + 1);
    if (_PyUnicode_UTF8(unicode) == NULL) {
        PyErr_NoMemory();
        Py_DECREF(bytes);
        return NULL;
    }
    _PyUnicode_UTF8_LENGTH(unicode) = PyBytes_GET_SIZE(bytes);
    memcpy(_PyUnicode_UTF8(unicode),
              PyBytes_AS_STRING(bytes),
              _PyUnicode_UTF8_LENGTH(unicode) + 1);
    Py_DECREF(bytes);
}

Le supplément de 3 octets sont pour l'UTF-8 de la représentation.


Vous demandez peut-être pourquoi la taille ne change pas lorsque la chaîne est quelque chose comme '40' ou 'plain ascii text'. C'est parce que si la chaîne est "compact ascii" de la représentation, Python n'est pas de la création d'un UTF-8 représentation. Il retourne la représentation ASCII directement, ce qui est déjà en UTF-8 valide:

#define PyUnicode_UTF8(op)                              \
    (assert(_PyUnicode_CHECK(op)),                      \
     assert(PyUnicode_IS_READY(op)),                    \
     PyUnicode_IS_COMPACT_ASCII(op) ?                   \
         ((char*)((PyASCIIObject*)(op) + 1)) :          \
         _PyUnicode_UTF8(op))

Vous pourriez aussi demander pourquoi la taille ne change pas pour quelque chose comme '1'. C'est U+FF11 FULLWIDTH CHIFFRES, qui int considère comme équivalente à '1'. C'est parce que l'une des premières étapes dans la chaîne-de-int processus est

asciidig = _PyUnicode_TransformDecimalAndSpaceToASCII(u);

qui convertit tous les caractères espace d' ' ' et convertit les caractères Unicode chiffres décimaux à l'correspondant chiffres ASCII. Cette conversion renvoie la chaîne d'origine si elle n'arrive pas à changer quoi que ce soit, mais quand c'est de faire des changements, il crée une nouvelle chaîne, et la chaîne est celui qui obtient un UTF-8 représentation créé.


Comme pour le cas où l'appelant int sur une chaîne dirait qu'il touche une autre, ceux-ci sont en fait le même objet de type string. Il y a beaucoup de conditions dans lesquelles Python de réutilisation des chaînes, tout aussi fermement dans Bizarre Détail de l'Implémentation des Terres que tout ce que nous avons discuté jusqu'à présent. Pour 'ñ', la réutilisation arrive parce que c'est une simple chaîne de caractères Latin-1 ('\x00'-'\xff'), et la mise en œuvre de magasins et réutilise ceux.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X