Sim*_*mme 67 python cpython python-2.7 python-3.x python-internals
__sizeof__在不同的Python对象上尝试使用魔术方法(特别是)我偶然发现了以下行为:
Python 2.7
>>> False.__sizeof__()
24
>>> True.__sizeof__()
24
Run Code Online (Sandbox Code Playgroud)
Python 3.x
>>> False.__sizeof__()
24
>>> True.__sizeof__()
28
Run Code Online (Sandbox Code Playgroud)
Python 3中改变了什么使得大小True超过了False?
Ant*_*ala 62
这是因为它是Python 2和3中bool的子类int.
>>> issubclass(bool, int)
True
Run Code Online (Sandbox Code Playgroud)
但int实施已经改变.
在Python 2中,int是32位或64位,取决于系统,而不是任意长度long.
在Python 3中,int是任意长度的 - longPython 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
Run Code Online (Sandbox Code Playgroud)
的long/ Python 3中int是可变长度对象,就像一个元组-当它被分配,足够的内存被分配以容纳所有来表示它所需的二进制数位.可变部分的长度存储在对象头中.0不需要二进制数字(其可变长度为0),但即使1溢出,也需要额外的数字.
即0表示为长度为0的二进制字符串:
<>
Run Code Online (Sandbox Code Playgroud)
1表示为30位二进制字符串:
<000000000000000000000000000001>
Run Code Online (Sandbox Code Playgroud)
Python中的默认配置使用30位uint32_t ; so 2**30 - 1在x86-64上仍然适合28个字节,并且2**30需要32个;
2**30 - 1 将作为
<111111111111111111111111111111>
Run Code Online (Sandbox Code Playgroud)
即所有30个值位设置为1; 2**30将需要更多,它将具有内部表示
<000000000000000000000000000001000000000000000000000000000000>
Run Code Online (Sandbox Code Playgroud)
至于True使用28个字节而不是24个 - 你不必担心.True是一个单例,因此在任何Python程序中总共只丢失4个字节,而不是每次使用4个字节True.
Wil*_*sem 20
这两个True和False是longobject小号在CPython的:
Run Code Online (Sandbox Code Playgroud)struct _longobject _Py_FalseStruct = { PyVarObject_HEAD_INIT(&PyBool_Type, 0) { 0 } }; struct _longobject _Py_TrueStruct = { PyVarObject_HEAD_INIT(&PyBool_Type, 1) { 1 } };
因此,您可以说布尔值是python-3.x 的子类,int其中True将值作为值1,并将False其作为值0.因此,我们PyVarObject_HEAD_INIT使用as作为type参数调用,并分别PyBool_Type使用ob_sizeas 0和value作为值1.
从python-3.x开始,现在已经没有long了:这些已被合并,并且int对象将根据数字的大小采用不同的值.
如果我们检查该longlobject类型的源代码,我们会看到:
Run Code Online (Sandbox Code Playgroud)/* 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]; };
长话短说,_longobject可以看作是一个"数字"数组,但你应该看到数字不是十进制数字,而是可以添加,乘以等的比特组.
现在正如评论中所指出的那样,它说:
Run Code Online (Sandbox Code Playgroud)zero is represented by ob_size == 0.
因此,如果值为零,则不添加任何数字,而对于小整数(CPython中小于2 30的值),则需要一位数,依此类推.
在python-2.x中,有两种类型的数字表示,ints(具有固定大小),你可以将其视为"一位数",而longs,具有多位数.由于a bool是一个子类int,True并且False占据了相同的空间.
看看在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 }Run Code Online (Sandbox Code Playgroud)
我还没有看到CPython代码,但我相信这与Python 3中的整数优化有关.可能正如long已经删除的那样,一些优化是统一的.int在Python 3中是任意大小的int - 与longPython 2 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
Run Code Online (Sandbox Code Playgroud)
对象标题的+字节应该完成等式.
| 归档时间: |
|
| 查看次数: |
2884 次 |
| 最近记录: |