__sizeof__在不同的Python对象上尝试魔术方法(尤其是),我偶然发现了以下行为:
Python 2.7
>>> False.__sizeof__()
24
>>> True.__sizeof__()
24
Python 3.x
>>> False.__sizeof__()
24
>>> True.__sizeof__()
28
Python 3中发生了什么变化,使大小True大于的大小False?
__sizeof__在不同的Python对象上尝试魔术方法(尤其是),我偶然发现了以下行为:
Python 2.7
>>> False.__sizeof__()
24
>>> True.__sizeof__()
24
Python 3.x
>>> False.__sizeof__()
24
>>> True.__sizeof__()
28
Python 3中发生了什么变化,使大小True大于的大小False?
sys.getsizeof和评估内存消耗__sizeof__(这会错过GC开销)将导致误导性结果。PyPy认为使用其中任何一个都是错误的。例如,整数5 <= i <= 256是CPython中的单例-[1, 1]且[1, 1, 1, 1]仅相差两个额外的指针大小。对于您的情况,您必须找出是否True和1共享相同的内存以获取其价值。
Answers:
这是因为它是Python 2和3bool的子类int。
>>> issubclass(bool, int)
True
但是int实现方式已经改变。
在Python 2中,int是32位或64位的那个,具体取决于系统,而不是任意长度long。
在Python 3中,它int是任意长度long的-Python 2的名称已重命名为int,而原始的Python 2则int完全删除了。
在Python 2中,对于长对象1L和具有完全相同的行为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
的long/ Python 3中int是可变长度对象,就像一个元组-当它被分配,足够的内存被分配以保持来表示它需要的所有二进制数字。可变部分的长度存储在对象头中。0不需要二进制数字(其可变长度为0),但是甚至会1溢出,并且需要额外的数字。
即0用长度为0的二进制字符串表示:
<>
1表示为30位二进制字符串:
<000000000000000000000000000001>
Python中的默认配置在;中使用30位uint32_t;so 2**30 - 1在x86-64上仍然可以容纳28个字节,并且2**30需要32个字节;
2**30 - 1 将呈现为
<111111111111111111111111111111>
即所有30个值位都设置为1;2 ** 30将需要更多,并且它将具有内部表示形式
<000000000000000000000000000001000000000000000000000000000000>
至于True使用28个字节而不是24个字节-您不必担心。True是一个单例,因此在任何Python程序中总共仅丢失4个字节,而不是每次使用4个字节True。
这两个True和False是longobject小号在CPython的:
struct _longobject _Py_FalseStruct = {
PyVarObject_HEAD_INIT(&PyBool_Type, 0)
{ 0 }
};
struct _longobject _Py_TrueStruct = {
PyVarObject_HEAD_INIT(&PyBool_Type, 1)
{ 1 }
};
因此,您可以说布尔是a的子类。 python-3.x int其中True以价值为核心1,False以价值为核心0。因此,我们拨打电话到PyVarObject_HEAD_INIT与作为type参数来参考PyBool_Type,并ob_size为价值0和1分别。
现在,因为 python-3.x,就long不再存在:它们已经合并,并且int对象将根据数字的大小采用不同的值。
如果我们检查longlobject类型的源代码,则会看到:
/* 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];
};
长话短说,an_longobject可以看作是“数字”的数组,但是在这里您应该看到数字不是十进制数字,而是可以加,乘等的位组。
现在,如注释中所指定,它说:
zero is represented by ob_size == 0.
因此,如果该值为零,则不添加数字,而对于较小的整数(在CPython中,值小于2 30)则为一位,依此类推。
在 python-2.x,数字有两种表示形式:ints(具有固定大小),您可以将其表示为“一位数字”,而longs则具有多位数字。由于abool是的子类int,因此True和False占用相同的空间。
我还没有看到CPython的代码,但是我认为这与Python 3中整数的优化有关long。intPython 3中的int是任意大小的int,与longPython 2中的int相同。由于bool存储方式与new相同int,因此会影响到两者。
有趣的部分:
>>> (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
+对象标头的字节应完成公式。
intPython 2long就是这样,确实int是被“丢弃”了
看看在CPython的代码,用于True和False
在内部,它表示为整数
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 }
01