different object size of True and False in Python3
Clash Royale CLAN TAG#URR8PPP
up vote
10
down vote
favorite
Experimenting with magic methods (__sizeof__
in particular) on different Python objects I stumbled over the following behaviour:
Python 2.7
>>> False.__sizeof__()
24
>>> True.__sizeof__()
24
Python 3.x
>>> False.__sizeof__()
24
>>> True.__sizeof__()
28
What changed in Python 3 that makes the size of True
greater than the size of False
?
python python-3.x python-2.7 cpython
 |Â
show 1 more comment
up vote
10
down vote
favorite
Experimenting with magic methods (__sizeof__
in particular) on different Python objects I stumbled over the following behaviour:
Python 2.7
>>> False.__sizeof__()
24
>>> True.__sizeof__()
24
Python 3.x
>>> False.__sizeof__()
24
>>> True.__sizeof__()
28
What changed in Python 3 that makes the size of True
greater than the size of False
?
python python-3.x python-2.7 cpython
2
dir
is totally irrelevant.
â juanpa.arrivillaga
32 mins ago
3
Related, the same behavior appears for0
vs1
â user3483203
30 mins ago
Reproduced earlier in CPython 3.4.9, CPython 3.3.7, CPython 3.2.6.
â wim
30 mins ago
1
Becausedir
returns a lot of things that have nothing to do with whatsys.sizeof
returns. Note,dir([1,2,3,4,5]) == dir()
butsys.getsizeof([1,2,3,4,5,]) != sys.getsizeof()
â juanpa.arrivillaga
27 mins ago
1
@roganjosh and just in general,dir
will give you every attribute accessible from an object, but you don't care about that, so for example, when you ask about the size of an object you generally don't want to include all the methods that belong to various classes that it has access to, do you?
â juanpa.arrivillaga
25 mins ago
 |Â
show 1 more comment
up vote
10
down vote
favorite
up vote
10
down vote
favorite
Experimenting with magic methods (__sizeof__
in particular) on different Python objects I stumbled over the following behaviour:
Python 2.7
>>> False.__sizeof__()
24
>>> True.__sizeof__()
24
Python 3.x
>>> False.__sizeof__()
24
>>> True.__sizeof__()
28
What changed in Python 3 that makes the size of True
greater than the size of False
?
python python-3.x python-2.7 cpython
Experimenting with magic methods (__sizeof__
in particular) on different Python objects I stumbled over the following behaviour:
Python 2.7
>>> False.__sizeof__()
24
>>> True.__sizeof__()
24
Python 3.x
>>> False.__sizeof__()
24
>>> True.__sizeof__()
28
What changed in Python 3 that makes the size of True
greater than the size of False
?
python python-3.x python-2.7 cpython
python python-3.x python-2.7 cpython
edited 16 mins ago
wim
151k46285413
151k46285413
asked 43 mins ago
Simon Fromme
1,295721
1,295721
2
dir
is totally irrelevant.
â juanpa.arrivillaga
32 mins ago
3
Related, the same behavior appears for0
vs1
â user3483203
30 mins ago
Reproduced earlier in CPython 3.4.9, CPython 3.3.7, CPython 3.2.6.
â wim
30 mins ago
1
Becausedir
returns a lot of things that have nothing to do with whatsys.sizeof
returns. Note,dir([1,2,3,4,5]) == dir()
butsys.getsizeof([1,2,3,4,5,]) != sys.getsizeof()
â juanpa.arrivillaga
27 mins ago
1
@roganjosh and just in general,dir
will give you every attribute accessible from an object, but you don't care about that, so for example, when you ask about the size of an object you generally don't want to include all the methods that belong to various classes that it has access to, do you?
â juanpa.arrivillaga
25 mins ago
 |Â
show 1 more comment
2
dir
is totally irrelevant.
â juanpa.arrivillaga
32 mins ago
3
Related, the same behavior appears for0
vs1
â user3483203
30 mins ago
Reproduced earlier in CPython 3.4.9, CPython 3.3.7, CPython 3.2.6.
â wim
30 mins ago
1
Becausedir
returns a lot of things that have nothing to do with whatsys.sizeof
returns. Note,dir([1,2,3,4,5]) == dir()
butsys.getsizeof([1,2,3,4,5,]) != sys.getsizeof()
â juanpa.arrivillaga
27 mins ago
1
@roganjosh and just in general,dir
will give you every attribute accessible from an object, but you don't care about that, so for example, when you ask about the size of an object you generally don't want to include all the methods that belong to various classes that it has access to, do you?
â juanpa.arrivillaga
25 mins ago
2
2
dir
is totally irrelevant.â juanpa.arrivillaga
32 mins ago
dir
is totally irrelevant.â juanpa.arrivillaga
32 mins ago
3
3
Related, the same behavior appears for
0
vs 1
â user3483203
30 mins ago
Related, the same behavior appears for
0
vs 1
â user3483203
30 mins ago
Reproduced earlier in CPython 3.4.9, CPython 3.3.7, CPython 3.2.6.
â wim
30 mins ago
Reproduced earlier in CPython 3.4.9, CPython 3.3.7, CPython 3.2.6.
â wim
30 mins ago
1
1
Because
dir
returns a lot of things that have nothing to do with what sys.sizeof
returns. Note, dir([1,2,3,4,5]) == dir()
but sys.getsizeof([1,2,3,4,5,]) != sys.getsizeof()
â juanpa.arrivillaga
27 mins ago
Because
dir
returns a lot of things that have nothing to do with what sys.sizeof
returns. Note, dir([1,2,3,4,5]) == dir()
but sys.getsizeof([1,2,3,4,5,]) != sys.getsizeof()
â juanpa.arrivillaga
27 mins ago
1
1
@roganjosh and just in general,
dir
will give you every attribute accessible from an object, but you don't care about that, so for example, when you ask about the size of an object you generally don't want to include all the methods that belong to various classes that it has access to, do you?â juanpa.arrivillaga
25 mins ago
@roganjosh and just in general,
dir
will give you every attribute accessible from an object, but you don't care about that, so for example, when you ask about the size of an object you generally don't want to include all the methods that belong to various classes that it has access to, do you?â juanpa.arrivillaga
25 mins ago
 |Â
show 1 more comment
4 Answers
4
active
oldest
votes
up vote
11
down vote
It is because bool
is a subclass of int
in both Python 2 and 3.
>>> issubclass(bool, int)
True
But the int
implementation has changed.
In Python 2, int
was the one that was 32 or 64 bits, depending on the system, as opposed to arbitrary-length long
.
In Python 3, int
is arbitrary-length - the long
of Python 2 was renamed to int
and the original Python 2 int
dropped altogether.
In Python 2 you get the exactly same behaviour for long objects 1L
and 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
The long
/Python 3 int
is a variable-length object, just like a tuple - when it is allocated, enough memory is allocated to hold all the binary digits required to represent it. The length of the variable part is stored in the object head. 0
requires no binary digits (its variable length is 0), but even 1
spills over, and requires extra digits.
I.e. 0
is represented as binary string of length 0:
<>
and 1 is represented as a 30-bit binary string:
<000000000000000000000000000001>
The default configuration in Python uses 30 bits in a uint32_t
; so 2**30 - 1
still fits in 28 bytes on x86-64, and 2**30
will require 32;
2**30 - 1
will be presented as
<111111111111111111111111111111>
i.e. all 30 value bits set to 1; 2**30 will need more, and it will have internal representation
<000000000000000000000000000000100000000000000000000000000000>
As for True
using 28 bytes instead of 24 - you need not worry. True
is a singleton and therefore only 4 bytes are lost in total in any Python program, not 4 for every usage of True
.
Yep, and long objects just use no extra pointer to represent 0
â juanpa.arrivillaga
23 mins ago
1
@roganjosh they are the same type. That doesn't mean they have the same size.sys.getsizeof([1,2,3,4,5])
andsys.getsizeof()
are not the same...
â juanpa.arrivillaga
21 mins ago
@roganjoshint
objects in Python 2 were always the same size.long
objects were arbitrarily-sized (like Python 3int
objects, indeed, Python 3int
objects are just Python 2 long objects)
â juanpa.arrivillaga
18 mins ago
@juanpa.arrivillaga now it makes sense to me :)
â roganjosh
7 mins ago
add a comment |Â
up vote
6
down vote
Both True
and False
are, in CPython longobject
s:
struct _longobject _Py_FalseStruct =
PyVarObject_HEAD_INIT(&PyBool_Type, 0)
0
;
struct _longobject _Py_TrueStruct =
PyVarObject_HEAD_INIT(&PyBool_Type, 1)
1
;
You thus can say, that a boolean is a subclass of a python-3.x int
where True
takes as value 1
, and False
takes as value 0
.
Now since python-3.x, there is no long
anymore: these have been merged, and the int
object will, depending on the size of the number, take a different value.
If we inspect the source code of the longlobject
type, we see:
/* 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];
;
To make a long story short, an _longobject
can be seen as an array of "digits", but you should here see digits not as decimal digits, but as groups of bits that thus can be added, multiplied, etc.
Now as is specified in the comment, it says that:
zero is represented by ob_size == 0.
So in case the value is zero, no digits are added, whereas for small integers (values less than 230 in CPython), it takes one digit, and so on.
add a comment |Â
up vote
3
down vote
I haven't seen CPython code for this, but I believe this has something to do with optimization of integers in python 3. Probably, as long
was dropped, some optimizations was unified. int
in PY3 is arbitrary-sized int â same as long
was in PY2. As bool
stores in the same way as new int
, it affects both.
Interesting part:
>>> (0).__sizeof__()
24
>>> (1).__sizeof__() # here 1 more "block" is allocated
28
>>> (2**30-1).__sizeof__() # this is maximum integer size fitting into 28
28
+ bytes for object headers should complete the equation.
Actually, now in Python 3,int
is just what Python 2long
was, it was reallyint
that was "dropped"
â juanpa.arrivillaga
24 mins ago
Internally â absolutely true, I'm talking about names, but thx for clarification
â Slam
24 mins ago
Indeed, in CPython 3 source code, it's still longobject
â juanpa.arrivillaga
22 mins ago
It is actually deoptimization... pessimization?
â Antti Haapala
3 mins ago
add a comment |Â
up vote
1
down vote
Take a look at the cpython code for True
and False
Internally it is represented as integer
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
I don't know why this was downvoted
â Antti Haapala
13 mins ago
I think i just was not as quick to answer properly as others :)
â Kamil Niski
12 mins ago
The answer only gets halfway there. It's represented as an integer.. yeah? And so what?
â wim
4 mins ago
@wim I don't see the need to explain it further since guys above already did great job at this. I don't want to duplicate content. Please refer to their answers.
â Kamil Niski
2 mins ago
add a comment |Â
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
11
down vote
It is because bool
is a subclass of int
in both Python 2 and 3.
>>> issubclass(bool, int)
True
But the int
implementation has changed.
In Python 2, int
was the one that was 32 or 64 bits, depending on the system, as opposed to arbitrary-length long
.
In Python 3, int
is arbitrary-length - the long
of Python 2 was renamed to int
and the original Python 2 int
dropped altogether.
In Python 2 you get the exactly same behaviour for long objects 1L
and 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
The long
/Python 3 int
is a variable-length object, just like a tuple - when it is allocated, enough memory is allocated to hold all the binary digits required to represent it. The length of the variable part is stored in the object head. 0
requires no binary digits (its variable length is 0), but even 1
spills over, and requires extra digits.
I.e. 0
is represented as binary string of length 0:
<>
and 1 is represented as a 30-bit binary string:
<000000000000000000000000000001>
The default configuration in Python uses 30 bits in a uint32_t
; so 2**30 - 1
still fits in 28 bytes on x86-64, and 2**30
will require 32;
2**30 - 1
will be presented as
<111111111111111111111111111111>
i.e. all 30 value bits set to 1; 2**30 will need more, and it will have internal representation
<000000000000000000000000000000100000000000000000000000000000>
As for True
using 28 bytes instead of 24 - you need not worry. True
is a singleton and therefore only 4 bytes are lost in total in any Python program, not 4 for every usage of True
.
Yep, and long objects just use no extra pointer to represent 0
â juanpa.arrivillaga
23 mins ago
1
@roganjosh they are the same type. That doesn't mean they have the same size.sys.getsizeof([1,2,3,4,5])
andsys.getsizeof()
are not the same...
â juanpa.arrivillaga
21 mins ago
@roganjoshint
objects in Python 2 were always the same size.long
objects were arbitrarily-sized (like Python 3int
objects, indeed, Python 3int
objects are just Python 2 long objects)
â juanpa.arrivillaga
18 mins ago
@juanpa.arrivillaga now it makes sense to me :)
â roganjosh
7 mins ago
add a comment |Â
up vote
11
down vote
It is because bool
is a subclass of int
in both Python 2 and 3.
>>> issubclass(bool, int)
True
But the int
implementation has changed.
In Python 2, int
was the one that was 32 or 64 bits, depending on the system, as opposed to arbitrary-length long
.
In Python 3, int
is arbitrary-length - the long
of Python 2 was renamed to int
and the original Python 2 int
dropped altogether.
In Python 2 you get the exactly same behaviour for long objects 1L
and 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
The long
/Python 3 int
is a variable-length object, just like a tuple - when it is allocated, enough memory is allocated to hold all the binary digits required to represent it. The length of the variable part is stored in the object head. 0
requires no binary digits (its variable length is 0), but even 1
spills over, and requires extra digits.
I.e. 0
is represented as binary string of length 0:
<>
and 1 is represented as a 30-bit binary string:
<000000000000000000000000000001>
The default configuration in Python uses 30 bits in a uint32_t
; so 2**30 - 1
still fits in 28 bytes on x86-64, and 2**30
will require 32;
2**30 - 1
will be presented as
<111111111111111111111111111111>
i.e. all 30 value bits set to 1; 2**30 will need more, and it will have internal representation
<000000000000000000000000000000100000000000000000000000000000>
As for True
using 28 bytes instead of 24 - you need not worry. True
is a singleton and therefore only 4 bytes are lost in total in any Python program, not 4 for every usage of True
.
Yep, and long objects just use no extra pointer to represent 0
â juanpa.arrivillaga
23 mins ago
1
@roganjosh they are the same type. That doesn't mean they have the same size.sys.getsizeof([1,2,3,4,5])
andsys.getsizeof()
are not the same...
â juanpa.arrivillaga
21 mins ago
@roganjoshint
objects in Python 2 were always the same size.long
objects were arbitrarily-sized (like Python 3int
objects, indeed, Python 3int
objects are just Python 2 long objects)
â juanpa.arrivillaga
18 mins ago
@juanpa.arrivillaga now it makes sense to me :)
â roganjosh
7 mins ago
add a comment |Â
up vote
11
down vote
up vote
11
down vote
It is because bool
is a subclass of int
in both Python 2 and 3.
>>> issubclass(bool, int)
True
But the int
implementation has changed.
In Python 2, int
was the one that was 32 or 64 bits, depending on the system, as opposed to arbitrary-length long
.
In Python 3, int
is arbitrary-length - the long
of Python 2 was renamed to int
and the original Python 2 int
dropped altogether.
In Python 2 you get the exactly same behaviour for long objects 1L
and 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
The long
/Python 3 int
is a variable-length object, just like a tuple - when it is allocated, enough memory is allocated to hold all the binary digits required to represent it. The length of the variable part is stored in the object head. 0
requires no binary digits (its variable length is 0), but even 1
spills over, and requires extra digits.
I.e. 0
is represented as binary string of length 0:
<>
and 1 is represented as a 30-bit binary string:
<000000000000000000000000000001>
The default configuration in Python uses 30 bits in a uint32_t
; so 2**30 - 1
still fits in 28 bytes on x86-64, and 2**30
will require 32;
2**30 - 1
will be presented as
<111111111111111111111111111111>
i.e. all 30 value bits set to 1; 2**30 will need more, and it will have internal representation
<000000000000000000000000000000100000000000000000000000000000>
As for True
using 28 bytes instead of 24 - you need not worry. True
is a singleton and therefore only 4 bytes are lost in total in any Python program, not 4 for every usage of True
.
It is because bool
is a subclass of int
in both Python 2 and 3.
>>> issubclass(bool, int)
True
But the int
implementation has changed.
In Python 2, int
was the one that was 32 or 64 bits, depending on the system, as opposed to arbitrary-length long
.
In Python 3, int
is arbitrary-length - the long
of Python 2 was renamed to int
and the original Python 2 int
dropped altogether.
In Python 2 you get the exactly same behaviour for long objects 1L
and 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
The long
/Python 3 int
is a variable-length object, just like a tuple - when it is allocated, enough memory is allocated to hold all the binary digits required to represent it. The length of the variable part is stored in the object head. 0
requires no binary digits (its variable length is 0), but even 1
spills over, and requires extra digits.
I.e. 0
is represented as binary string of length 0:
<>
and 1 is represented as a 30-bit binary string:
<000000000000000000000000000001>
The default configuration in Python uses 30 bits in a uint32_t
; so 2**30 - 1
still fits in 28 bytes on x86-64, and 2**30
will require 32;
2**30 - 1
will be presented as
<111111111111111111111111111111>
i.e. all 30 value bits set to 1; 2**30 will need more, and it will have internal representation
<000000000000000000000000000000100000000000000000000000000000>
As for True
using 28 bytes instead of 24 - you need not worry. True
is a singleton and therefore only 4 bytes are lost in total in any Python program, not 4 for every usage of True
.
edited 5 mins ago
answered 28 mins ago
Antti Haapala
76.5k16143189
76.5k16143189
Yep, and long objects just use no extra pointer to represent 0
â juanpa.arrivillaga
23 mins ago
1
@roganjosh they are the same type. That doesn't mean they have the same size.sys.getsizeof([1,2,3,4,5])
andsys.getsizeof()
are not the same...
â juanpa.arrivillaga
21 mins ago
@roganjoshint
objects in Python 2 were always the same size.long
objects were arbitrarily-sized (like Python 3int
objects, indeed, Python 3int
objects are just Python 2 long objects)
â juanpa.arrivillaga
18 mins ago
@juanpa.arrivillaga now it makes sense to me :)
â roganjosh
7 mins ago
add a comment |Â
Yep, and long objects just use no extra pointer to represent 0
â juanpa.arrivillaga
23 mins ago
1
@roganjosh they are the same type. That doesn't mean they have the same size.sys.getsizeof([1,2,3,4,5])
andsys.getsizeof()
are not the same...
â juanpa.arrivillaga
21 mins ago
@roganjoshint
objects in Python 2 were always the same size.long
objects were arbitrarily-sized (like Python 3int
objects, indeed, Python 3int
objects are just Python 2 long objects)
â juanpa.arrivillaga
18 mins ago
@juanpa.arrivillaga now it makes sense to me :)
â roganjosh
7 mins ago
Yep, and long objects just use no extra pointer to represent 0
â juanpa.arrivillaga
23 mins ago
Yep, and long objects just use no extra pointer to represent 0
â juanpa.arrivillaga
23 mins ago
1
1
@roganjosh they are the same type. That doesn't mean they have the same size.
sys.getsizeof([1,2,3,4,5])
and sys.getsizeof()
are not the same...â juanpa.arrivillaga
21 mins ago
@roganjosh they are the same type. That doesn't mean they have the same size.
sys.getsizeof([1,2,3,4,5])
and sys.getsizeof()
are not the same...â juanpa.arrivillaga
21 mins ago
@roganjosh
int
objects in Python 2 were always the same size. long
objects were arbitrarily-sized (like Python 3 int
objects, indeed, Python 3 int
objects are just Python 2 long objects)â juanpa.arrivillaga
18 mins ago
@roganjosh
int
objects in Python 2 were always the same size. long
objects were arbitrarily-sized (like Python 3 int
objects, indeed, Python 3 int
objects are just Python 2 long objects)â juanpa.arrivillaga
18 mins ago
@juanpa.arrivillaga now it makes sense to me :)
â roganjosh
7 mins ago
@juanpa.arrivillaga now it makes sense to me :)
â roganjosh
7 mins ago
add a comment |Â
up vote
6
down vote
Both True
and False
are, in CPython longobject
s:
struct _longobject _Py_FalseStruct =
PyVarObject_HEAD_INIT(&PyBool_Type, 0)
0
;
struct _longobject _Py_TrueStruct =
PyVarObject_HEAD_INIT(&PyBool_Type, 1)
1
;
You thus can say, that a boolean is a subclass of a python-3.x int
where True
takes as value 1
, and False
takes as value 0
.
Now since python-3.x, there is no long
anymore: these have been merged, and the int
object will, depending on the size of the number, take a different value.
If we inspect the source code of the longlobject
type, we see:
/* 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];
;
To make a long story short, an _longobject
can be seen as an array of "digits", but you should here see digits not as decimal digits, but as groups of bits that thus can be added, multiplied, etc.
Now as is specified in the comment, it says that:
zero is represented by ob_size == 0.
So in case the value is zero, no digits are added, whereas for small integers (values less than 230 in CPython), it takes one digit, and so on.
add a comment |Â
up vote
6
down vote
Both True
and False
are, in CPython longobject
s:
struct _longobject _Py_FalseStruct =
PyVarObject_HEAD_INIT(&PyBool_Type, 0)
0
;
struct _longobject _Py_TrueStruct =
PyVarObject_HEAD_INIT(&PyBool_Type, 1)
1
;
You thus can say, that a boolean is a subclass of a python-3.x int
where True
takes as value 1
, and False
takes as value 0
.
Now since python-3.x, there is no long
anymore: these have been merged, and the int
object will, depending on the size of the number, take a different value.
If we inspect the source code of the longlobject
type, we see:
/* 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];
;
To make a long story short, an _longobject
can be seen as an array of "digits", but you should here see digits not as decimal digits, but as groups of bits that thus can be added, multiplied, etc.
Now as is specified in the comment, it says that:
zero is represented by ob_size == 0.
So in case the value is zero, no digits are added, whereas for small integers (values less than 230 in CPython), it takes one digit, and so on.
add a comment |Â
up vote
6
down vote
up vote
6
down vote
Both True
and False
are, in CPython longobject
s:
struct _longobject _Py_FalseStruct =
PyVarObject_HEAD_INIT(&PyBool_Type, 0)
0
;
struct _longobject _Py_TrueStruct =
PyVarObject_HEAD_INIT(&PyBool_Type, 1)
1
;
You thus can say, that a boolean is a subclass of a python-3.x int
where True
takes as value 1
, and False
takes as value 0
.
Now since python-3.x, there is no long
anymore: these have been merged, and the int
object will, depending on the size of the number, take a different value.
If we inspect the source code of the longlobject
type, we see:
/* 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];
;
To make a long story short, an _longobject
can be seen as an array of "digits", but you should here see digits not as decimal digits, but as groups of bits that thus can be added, multiplied, etc.
Now as is specified in the comment, it says that:
zero is represented by ob_size == 0.
So in case the value is zero, no digits are added, whereas for small integers (values less than 230 in CPython), it takes one digit, and so on.
Both True
and False
are, in CPython longobject
s:
struct _longobject _Py_FalseStruct =
PyVarObject_HEAD_INIT(&PyBool_Type, 0)
0
;
struct _longobject _Py_TrueStruct =
PyVarObject_HEAD_INIT(&PyBool_Type, 1)
1
;
You thus can say, that a boolean is a subclass of a python-3.x int
where True
takes as value 1
, and False
takes as value 0
.
Now since python-3.x, there is no long
anymore: these have been merged, and the int
object will, depending on the size of the number, take a different value.
If we inspect the source code of the longlobject
type, we see:
/* 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];
;
To make a long story short, an _longobject
can be seen as an array of "digits", but you should here see digits not as decimal digits, but as groups of bits that thus can be added, multiplied, etc.
Now as is specified in the comment, it says that:
zero is represented by ob_size == 0.
So in case the value is zero, no digits are added, whereas for small integers (values less than 230 in CPython), it takes one digit, and so on.
answered 23 mins ago
Willem Van Onsem
134k16126214
134k16126214
add a comment |Â
add a comment |Â
up vote
3
down vote
I haven't seen CPython code for this, but I believe this has something to do with optimization of integers in python 3. Probably, as long
was dropped, some optimizations was unified. int
in PY3 is arbitrary-sized int â same as long
was in PY2. As bool
stores in the same way as new int
, it affects both.
Interesting part:
>>> (0).__sizeof__()
24
>>> (1).__sizeof__() # here 1 more "block" is allocated
28
>>> (2**30-1).__sizeof__() # this is maximum integer size fitting into 28
28
+ bytes for object headers should complete the equation.
Actually, now in Python 3,int
is just what Python 2long
was, it was reallyint
that was "dropped"
â juanpa.arrivillaga
24 mins ago
Internally â absolutely true, I'm talking about names, but thx for clarification
â Slam
24 mins ago
Indeed, in CPython 3 source code, it's still longobject
â juanpa.arrivillaga
22 mins ago
It is actually deoptimization... pessimization?
â Antti Haapala
3 mins ago
add a comment |Â
up vote
3
down vote
I haven't seen CPython code for this, but I believe this has something to do with optimization of integers in python 3. Probably, as long
was dropped, some optimizations was unified. int
in PY3 is arbitrary-sized int â same as long
was in PY2. As bool
stores in the same way as new int
, it affects both.
Interesting part:
>>> (0).__sizeof__()
24
>>> (1).__sizeof__() # here 1 more "block" is allocated
28
>>> (2**30-1).__sizeof__() # this is maximum integer size fitting into 28
28
+ bytes for object headers should complete the equation.
Actually, now in Python 3,int
is just what Python 2long
was, it was reallyint
that was "dropped"
â juanpa.arrivillaga
24 mins ago
Internally â absolutely true, I'm talking about names, but thx for clarification
â Slam
24 mins ago
Indeed, in CPython 3 source code, it's still longobject
â juanpa.arrivillaga
22 mins ago
It is actually deoptimization... pessimization?
â Antti Haapala
3 mins ago
add a comment |Â
up vote
3
down vote
up vote
3
down vote
I haven't seen CPython code for this, but I believe this has something to do with optimization of integers in python 3. Probably, as long
was dropped, some optimizations was unified. int
in PY3 is arbitrary-sized int â same as long
was in PY2. As bool
stores in the same way as new int
, it affects both.
Interesting part:
>>> (0).__sizeof__()
24
>>> (1).__sizeof__() # here 1 more "block" is allocated
28
>>> (2**30-1).__sizeof__() # this is maximum integer size fitting into 28
28
+ bytes for object headers should complete the equation.
I haven't seen CPython code for this, but I believe this has something to do with optimization of integers in python 3. Probably, as long
was dropped, some optimizations was unified. int
in PY3 is arbitrary-sized int â same as long
was in PY2. As bool
stores in the same way as new int
, it affects both.
Interesting part:
>>> (0).__sizeof__()
24
>>> (1).__sizeof__() # here 1 more "block" is allocated
28
>>> (2**30-1).__sizeof__() # this is maximum integer size fitting into 28
28
+ bytes for object headers should complete the equation.
edited 23 mins ago
answered 25 mins ago
Slam
3,34511832
3,34511832
Actually, now in Python 3,int
is just what Python 2long
was, it was reallyint
that was "dropped"
â juanpa.arrivillaga
24 mins ago
Internally â absolutely true, I'm talking about names, but thx for clarification
â Slam
24 mins ago
Indeed, in CPython 3 source code, it's still longobject
â juanpa.arrivillaga
22 mins ago
It is actually deoptimization... pessimization?
â Antti Haapala
3 mins ago
add a comment |Â
Actually, now in Python 3,int
is just what Python 2long
was, it was reallyint
that was "dropped"
â juanpa.arrivillaga
24 mins ago
Internally â absolutely true, I'm talking about names, but thx for clarification
â Slam
24 mins ago
Indeed, in CPython 3 source code, it's still longobject
â juanpa.arrivillaga
22 mins ago
It is actually deoptimization... pessimization?
â Antti Haapala
3 mins ago
Actually, now in Python 3,
int
is just what Python 2 long
was, it was really int
that was "dropped"â juanpa.arrivillaga
24 mins ago
Actually, now in Python 3,
int
is just what Python 2 long
was, it was really int
that was "dropped"â juanpa.arrivillaga
24 mins ago
Internally â absolutely true, I'm talking about names, but thx for clarification
â Slam
24 mins ago
Internally â absolutely true, I'm talking about names, but thx for clarification
â Slam
24 mins ago
Indeed, in CPython 3 source code, it's still longobject
â juanpa.arrivillaga
22 mins ago
Indeed, in CPython 3 source code, it's still longobject
â juanpa.arrivillaga
22 mins ago
It is actually deoptimization... pessimization?
â Antti Haapala
3 mins ago
It is actually deoptimization... pessimization?
â Antti Haapala
3 mins ago
add a comment |Â
up vote
1
down vote
Take a look at the cpython code for True
and False
Internally it is represented as integer
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
I don't know why this was downvoted
â Antti Haapala
13 mins ago
I think i just was not as quick to answer properly as others :)
â Kamil Niski
12 mins ago
The answer only gets halfway there. It's represented as an integer.. yeah? And so what?
â wim
4 mins ago
@wim I don't see the need to explain it further since guys above already did great job at this. I don't want to duplicate content. Please refer to their answers.
â Kamil Niski
2 mins ago
add a comment |Â
up vote
1
down vote
Take a look at the cpython code for True
and False
Internally it is represented as integer
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
I don't know why this was downvoted
â Antti Haapala
13 mins ago
I think i just was not as quick to answer properly as others :)
â Kamil Niski
12 mins ago
The answer only gets halfway there. It's represented as an integer.. yeah? And so what?
â wim
4 mins ago
@wim I don't see the need to explain it further since guys above already did great job at this. I don't want to duplicate content. Please refer to their answers.
â Kamil Niski
2 mins ago
add a comment |Â
up vote
1
down vote
up vote
1
down vote
Take a look at the cpython code for True
and False
Internally it is represented as integer
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
Take a look at the cpython code for True
and False
Internally it is represented as integer
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
edited 16 mins ago
answered 26 mins ago
Kamil Niski
1,915111
1,915111
I don't know why this was downvoted
â Antti Haapala
13 mins ago
I think i just was not as quick to answer properly as others :)
â Kamil Niski
12 mins ago
The answer only gets halfway there. It's represented as an integer.. yeah? And so what?
â wim
4 mins ago
@wim I don't see the need to explain it further since guys above already did great job at this. I don't want to duplicate content. Please refer to their answers.
â Kamil Niski
2 mins ago
add a comment |Â
I don't know why this was downvoted
â Antti Haapala
13 mins ago
I think i just was not as quick to answer properly as others :)
â Kamil Niski
12 mins ago
The answer only gets halfway there. It's represented as an integer.. yeah? And so what?
â wim
4 mins ago
@wim I don't see the need to explain it further since guys above already did great job at this. I don't want to duplicate content. Please refer to their answers.
â Kamil Niski
2 mins ago
I don't know why this was downvoted
â Antti Haapala
13 mins ago
I don't know why this was downvoted
â Antti Haapala
13 mins ago
I think i just was not as quick to answer properly as others :)
â Kamil Niski
12 mins ago
I think i just was not as quick to answer properly as others :)
â Kamil Niski
12 mins ago
The answer only gets halfway there. It's represented as an integer.. yeah? And so what?
â wim
4 mins ago
The answer only gets halfway there. It's represented as an integer.. yeah? And so what?
â wim
4 mins ago
@wim I don't see the need to explain it further since guys above already did great job at this. I don't want to duplicate content. Please refer to their answers.
â Kamil Niski
2 mins ago
@wim I don't see the need to explain it further since guys above already did great job at this. I don't want to duplicate content. Please refer to their answers.
â Kamil Niski
2 mins ago
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53015922%2fdifferent-object-size-of-true-and-false-in-python3%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
2
dir
is totally irrelevant.â juanpa.arrivillaga
32 mins ago
3
Related, the same behavior appears for
0
vs1
â user3483203
30 mins ago
Reproduced earlier in CPython 3.4.9, CPython 3.3.7, CPython 3.2.6.
â wim
30 mins ago
1
Because
dir
returns a lot of things that have nothing to do with whatsys.sizeof
returns. Note,dir([1,2,3,4,5]) == dir()
butsys.getsizeof([1,2,3,4,5,]) != sys.getsizeof()
â juanpa.arrivillaga
27 mins ago
1
@roganjosh and just in general,
dir
will give you every attribute accessible from an object, but you don't care about that, so for example, when you ask about the size of an object you generally don't want to include all the methods that belong to various classes that it has access to, do you?â juanpa.arrivillaga
25 mins ago