Experimentieren mit magischen Methoden (__sizeof__
insbesondere) auf verschiedenen Python Objekten bin ich auf folgendes Verhalten gestoßen:
Python 2.7
>>> False.__sizeof__()
24
>>> True.__sizeof__()
24
Python 3.x
>>> False.__sizeof__()
24
>>> True.__sizeof__()
28
Was hat sich in Python 3 geändert, das die Größe von True
größer macht als die Größe von False
?
Dies liegt daran, dass bool
eine Unterklasse von int
in Python 2 und 3 ist.
>>> issubclass(bool, int)
True
Aber die Implementierung von int
hat sich geändert.
In Python 2 war int
derjenige, der 32 oder 64 Bit betrug, abhängig vom System, im Gegensatz zu long
mit willkürlicher Länge.
In Python 3 ist int
beliebig lang - der long
von Python 2 wurde in int
und der ursprüngliche Python umbenannt 2 int
insgesamt fallen gelassen.
In Python 2 erhalten Sie dasselbe Verhalten für long Objekte 1L
Und 0L
:
Python 2.7.15rc1 (default, Apr 15 2018, 21:51:34)
[GCC 7.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.getsizeof(1L)
28
>>> sys.getsizeof(0L)
24
Das long
/Python 3 int
ist ein Objekt mit variabler Länge, genau wie ein Tupel. Wenn es zugewiesen wird, wird genügend Speicher zugewiesen, um alle für seine Darstellung erforderlichen Binärziffern aufzunehmen. Die Länge des variablen Teils wird im Objektkopf gespeichert. 0
Erfordert keine Binärziffern (die variable Länge ist 0), aber auch 1
Geht über und erfordert zusätzliche Ziffern.
Das heißt 0
Wird als binärer String der Länge 0 dargestellt:
<>
und 1 wird als 30-Bit-Binärzeichenfolge dargestellt:
<000000000000000000000000000001>
Die Standardkonfiguration in Python verwendet Bits in einem uint32_t
; so 2**30 - 1
Passt immer noch in 28 Bytes auf x86-64 und 2**30
Benötigt 32;
2**30 - 1
Wird dargestellt als
<111111111111111111111111111111>
alle 30 Wertebits auf 1 gesetzt; 2 ** 30 wird mehr brauchen, und es wird interne Vertretung haben
<000000000000000000000000000001000000000000000000000000000000>
Wie für True
mit 28 Bytes anstelle von 24 - Sie brauchen sich keine Sorgen zu machen. True
ist ein Singleton und daher gehen nur 4 Bytes in total in Python Programm, nicht 4 für jede Verwendung von True
.
Sowohl True
als auch False
sind longobject
s in CPython:
struct _longobject _Py_FalseStruct = { PyVarObject_HEAD_INIT(&PyBool_Type, 0) { 0 } }; struct _longobject _Py_TrueStruct = { PyVarObject_HEAD_INIT(&PyBool_Type, 1) { 1 } };
Man kann also sagen, dass ein Boolescher Wert eine Unterklasse von python-3.xint
ist, wobei True
den Wert 1
Annimmt, und False
nimmt als Wert 0
an. Wir rufen also PyVarObject_HEAD_INIT
mit als type
-Parameter auf PyBool_Type
Und mit ob_size
Als Wert 0
Bzw. 1
.
Seit python-3.x gibt es kein long
mehr: Diese wurden zusammengeführt, und das int
-Objekt wird abhängig von der Größe des Zahl, nehmen Sie einen anderen Wert.
Wenn wir den Quellcode des Typs longlobject
untersuchen, sehen wir:
/* Long integer representation. The absolute value of a number is equal to SUM(for i=0 through abs(ob_size)-1) ob_digit[i] * 2**(SHIFT*i) Negative numbers are represented with ob_size < 0; zero is represented by ob_size == 0. In a normalized number, ob_digit[abs(ob_size)-1] (the most significant digit) is never zero. Also, in all cases, for all valid i, 0 <= ob_digit[i] <= MASK. The allocation function takes care of allocating extra memory so that ob_digit[0] ... ob_digit[abs(ob_size)-1] are actually available. CAUTION: Generic code manipulating subtypes of PyVarObject has to aware that ints abuse ob_size's sign bit. */ struct _longobject { PyObject_VAR_HEAD digit ob_digit[1]; };
Um es kurz zu machen, ein _longobject
Kann als ein Array von "Ziffern" gesehen werden, aber Sie sollten hier Ziffern nicht als Dezimalziffern sehen, sondern als Gruppen von Bits, die auf diese Weise addiert, multipliziert usw. Werden können .
Nun, wie im Kommentar angegeben, heißt es:
zero is represented by ob_size == 0.
Für den Fall, dass der Wert Null ist, werden keine Ziffern hinzugefügt, während für kleine ganze Zahlen (Werte kleiner als 2)30 in CPython) dauert es eine Ziffer und so weiter.
In python-2.x gab es zwei Arten von Darstellungen für Zahlen, int
s (mit einer festen Größe), Sie konnten dies als "eine Ziffer" und long
s mit mehreren Ziffern. Da eine bool
eine Unterklasse von int
war, nahmen sowohl True
als auch False
den gleichen Platz ein.
Schauen Sie sich den cpython code für True
und False
an
Intern wird es als Ganzzahl dargestellt
PyTypeObject PyBool_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"bool",
sizeof(struct _longobject),
0,
0, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
bool_repr, /* tp_repr */
&bool_as_number, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
bool_repr, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
bool_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
&PyLong_Type, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
bool_new, /* tp_new */
};
/* The objects representing bool values False and True */
struct _longobject _Py_FalseStruct = {
PyVarObject_HEAD_INIT(&PyBool_Type, 0)
{ 0 }
};
struct _longobject _Py_TrueStruct = {
PyVarObject_HEAD_INIT(&PyBool_Type, 1)
{ 1 }
Ich habe keinen CPython-Code dafür gesehen, aber ich glaube, das hat etwas mit der Optimierung von Ganzzahlen in Python 3 zu tun. Wahrscheinlich wurden einige Optimierungen vereinheitlicht, als long
gelöscht wurde. int
in Python 3 hat eine beliebige Größe int - das gleiche wie long
in Python 2. Da bool
auf die gleiche Weise wie neu int
gespeichert wird, es betrifft beides.
Interessanter Teil:
>>> (0).__sizeof__()
24
>>> (1).__sizeof__() # Here one more "block" is allocated
28
>>> (2**30-1).__sizeof__() # This is the maximum integer size fitting into 28
28
+ Bytes für Objektüberschriften sollten die Gleichung vervollständigen.