Comprendre l'allocation de mémoire pour les grands entiers en Python
comment Python affecte-t-il la mémoire pour les grands nombres entiers?
un type int
a une taille de 28 bytes
et comme je continue à augmenter la valeur du int
, la taille augmente par incréments de 4 bytes
.
-
pourquoi
28 bytes
initialement pour toute valeur aussi basse que1
? -
pourquoi des incréments de
4 bytes
?
PS: J'exécute Python 3.5.2 sur une machine x86_64 (64 bits). Tous les indicateurs/ressources / PEPs sur la façon dont les interprètes (3.0+) travaillent sur de tels nombres énormes est ce que je cherche.
Code illustrant les dimensions:
>>> a=1
>>> print(a.__sizeof__())
28
>>> a=1024
>>> print(a.__sizeof__())
28
>>> a=1024*1024*1024
>>> print(a.__sizeof__())
32
>>> a=1024*1024*1024*1024
>>> print(a.__sizeof__())
32
>>> a=1024*1024*1024*1024*1024*1024
>>> a
1152921504606846976
>>> print(a.__sizeof__())
36
2 réponses
pourquoi
28
octets initialement pour une valeur aussi basse que1
?
je crois @bgusach a répondu que complètement; Python utilise C
structures pour représenter des objets dans le monde de Python, tous les objets y compris int
s :
struct _longobject {
PyObject_VAR_HEAD
digit ob_digit[1];
};
PyObject_VAR_HEAD
est une macro qui, lorsqu'elle est étendue, ajoute un autre champ dans la structure (champ PyVarObject
qui est spécifiquement utilisé pour les objets qui ont une certaine notion de longueur) et, ob_digits
est un tableau contenant la valeur du nombre. La chaudière-plaque dans la taille vient de cette structure, pour les petits et grands nombres de Python.
pourquoi incréments de
4
octets?
parce que, quand un plus grand nombre est créé, la taille (en octets) est un multiple du sizeof(digit)
; vous pouvez voir que dans _PyLong_New
où l'attribution de la mémoire pour un nouveau longobject
est effectuée avec PyObject_MALLOC
:
/* Number of bytes needed is: offsetof(PyLongObject, ob_digit) +
sizeof(digit)*size. Previous incarnations of this code used
sizeof(PyVarObject) instead of the offsetof, but this risks being
incorrect in the presence of padding between the PyVarObject header
and the digits. */
if (size > (Py_ssize_t)MAX_LONG_DIGITS) {
PyErr_SetString(PyExc_OverflowError,
"too many digits in integer");
return NULL;
}
result = PyObject_MALLOC(offsetof(PyLongObject, ob_digit) +
size*sizeof(digit));
offsetof(PyLongObject, ob_digit)
est la "plaque chauffante" (en octets) pour le long objet qui n'est pas lié à la conservation de sa valeur.
digit
est défini dans le fichier d'en-tête struct _longobject
comme typedef
pour uint32
:
typedef uint32_t digit;
et sizeof(uint32_t)
est 4
octets. C'est le montant par lequel vous verrez la taille en octets augmenter lorsque l'argument size
augmente à _PyLong_New
.
bien sûr, C'est comme ça que C
Python a choisi de l'implémenter. C'est un détail d'implémentation et en tant que tel vous ne trouverez pas beaucoup d'informations dans les Pep. Le la liste de diffusion python-dev tiendra des discussions sur l'implémentation si vous pouvez trouver le thread correspondant :-).
de toute façon, vous pourriez trouver des comportements différents dans d'autres implémentations populaires, alors ne le prenez pas pour acquis.
c'est facile. Le int
de Python n'est pas le genre de primitif auquel on peut être habitué à partir d'autres langues, mais un objet à part entière, avec ses méthodes et tout le reste. C'est là que la surcharge.
alors, vous avez la charge elle-même, l'entier qui est représenté. Et il n'y a pas de limite à cela, sauf votre mémoire.
la taille d'un Python int
est ce dont il a besoin pour représenter le nombre plus un peu de surcharge.
si vous souhaitez lire la suite, consultez la partie de la documentation :
les entiers ont une précision illimitée