Python 3中不同的对象大小True和False

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

这两个TrueFalselongobject小号在CPython的:

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)

因此,您可以说布尔值是 的子类,int其中True将值作为值1,并将False其作为值0.因此,我们PyVarObject_HEAD_INIT使用as作为type参数调用,并分别PyBool_Type使用ob_sizeas 0和value作为值1.

,现在已经没有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];
};
Run Code Online (Sandbox Code Playgroud)

长话短说,_longobject可以看作是一个"数字"数组,但你应该看到数字不是十进制数字,而是可以添加,乘以等的比特组.

现在正如评论中所指出的那样,它说:

   zero is represented by ob_size == 0.
Run Code Online (Sandbox Code Playgroud)

因此,如果值为零,则不添加任何数字,而对于小整数(CPython中小于2 30的值),则需要一位数,依此类推.

,有两种类型的数字表示,ints(具有固定大小),你可以将其视为"一位数",而longs,具有多位数.由于a bool是一个子类int,True并且False占据了相同的空间.


Kam*_*ski 6

看看在CPython的代码,用于TrueFalse

在内部,它表示为整数

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)

  • 我想是的,但这取决于你.如果你等待它可能得到+3然后删除你可能会获得[纪律](https://stackoverflow.com/help/badges/37/disciplined)徽章...... :) (4认同)
  • 答案只有一半到那里.它表示为整数..是吗?什么呢? (2认同)

Sla*_*lam 6

我还没有看到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)

对象标题的+字节应该完成等式.