-
-
Notifications
You must be signed in to change notification settings - Fork 32.3k
gh-129675: Update documentation for tp_basicsize & tp_itemsize #129850
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -537,6 +537,9 @@ PyVarObject Slots | |
initialized to zero. For :ref:`dynamically allocated type objects | ||
<heap-types>`, this field has a special internal meaning. | ||
|
||
This field should be accessed using the :c:func:`Py_SIZE()` and | ||
:c:func:`Py_SET_SIZE()` macros. | ||
|
||
**Inheritance:** | ||
|
||
This field is not inherited by subtypes. | ||
|
@@ -587,47 +590,86 @@ and :c:data:`PyType_Type` effectively act as defaults.) | |
|
||
|
||
.. c:member:: Py_ssize_t PyTypeObject.tp_basicsize | ||
Py_ssize_t PyTypeObject.tp_itemsize | ||
Py_ssize_t PyTypeObject.tp_itemsize | ||
|
||
These fields allow calculating the size in bytes of instances of the type. | ||
|
||
There are two kinds of types: types with fixed-length instances have a zero | ||
:c:member:`~PyTypeObject.tp_itemsize` field, types with variable-length instances have a non-zero | ||
:c:member:`~PyTypeObject.tp_itemsize` field. For a type with fixed-length instances, all | ||
instances have the same size, given in :c:member:`~PyTypeObject.tp_basicsize`. | ||
:c:member:`!tp_itemsize` field, types with variable-length instances have a non-zero | ||
ZeroIntensity marked this conversation as resolved.
Show resolved
Hide resolved
|
||
:c:member:`!tp_itemsize` field. For a type with fixed-length instances, all | ||
instances have the same size, given in :c:member:`!tp_basicsize`. | ||
(Exceptions to this rule can be made using | ||
:c:func:`PyUnstable_Object_GC_NewWithExtraData`.) | ||
|
||
For a type with variable-length instances, the instances must have an | ||
:c:member:`~PyVarObject.ob_size` field, and the instance size is :c:member:`~PyTypeObject.tp_basicsize` plus N | ||
times :c:member:`~PyTypeObject.tp_itemsize`, where N is the "length" of the object. The value of | ||
N is typically stored in the instance's :c:member:`~PyVarObject.ob_size` field. There are | ||
exceptions: for example, ints use a negative :c:member:`~PyVarObject.ob_size` to indicate a | ||
negative number, and N is ``abs(ob_size)`` there. Also, the presence of an | ||
Comment on lines
-603
to
-604
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @markshannon FWIW, here's another piece of documentation that says |
||
:c:member:`~PyVarObject.ob_size` field in the instance layout doesn't mean that the instance | ||
structure is variable-length (for example, the structure for the list type has | ||
fixed-length instances, yet those instances have a meaningful :c:member:`~PyVarObject.ob_size` | ||
field). | ||
|
||
The basic size includes the fields in the instance declared by the macro | ||
:c:macro:`PyObject_HEAD` or :c:macro:`PyObject_VAR_HEAD` (whichever is used to | ||
declare the instance struct) and this in turn includes the :c:member:`~PyObject._ob_prev` and | ||
:c:member:`~PyObject._ob_next` fields if they are present. This means that the only correct | ||
way to get an initializer for the :c:member:`~PyTypeObject.tp_basicsize` is to use the | ||
``sizeof`` operator on the struct used to declare the instance layout. | ||
The basic size does not include the GC header size. | ||
:c:member:`~PyVarObject.ob_size` field, and the instance size is | ||
:c:member:`!tp_basicsize` plus N times :c:member:`!tp_itemsize`, | ||
where N is the "length" of the object. | ||
|
||
Functions like :c:func:`PyObject_NewVar` will take the value of N as an | ||
argument, and store in the instance's :c:member:`~PyVarObject.ob_size` field. | ||
Note that the :c:member:`~PyVarObject.ob_size` field may later be used for | ||
other purposes. For example, :py:type:`int` instances use the bits of | ||
:c:member:`~PyVarObject.ob_size` in an implementation-defined | ||
way; the underlying storage and its size should be acessed using | ||
:c:func:`PyLong_Export`. | ||
ZeroIntensity marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
.. note:: | ||
|
||
A note about alignment: if the variable items require a particular alignment, | ||
this should be taken care of by the value of :c:member:`~PyTypeObject.tp_basicsize`. Example: | ||
suppose a type implements an array of ``double``. :c:member:`~PyTypeObject.tp_itemsize` is | ||
``sizeof(double)``. It is the programmer's responsibility that | ||
:c:member:`~PyTypeObject.tp_basicsize` is a multiple of ``sizeof(double)`` (assuming this is the | ||
alignment requirement for ``double``). | ||
The :c:member:`~PyVarObject.ob_size` field should be accessed using | ||
the :c:func:`Py_SIZE()` and :c:func:`Py_SET_SIZE()` macros. | ||
|
||
For any type with variable-length instances, this field must not be ``NULL``. | ||
Also, the presence of an :c:member:`~PyVarObject.ob_size` field in the | ||
instance layout doesn't mean that the instance structure is variable-length. | ||
For example, the :py:type:`list` type has fixed-length instances, yet those | ||
instances have a :c:member:`~PyVarObject.ob_size` field. | ||
(As with :py:type:`int`, avoid reading lists' :c:member:`!ob_size` directly. | ||
Call :c:func:`PyList_Size` instead.) | ||
|
||
The :c:member:`!tp_basicsize` includes size needed for data of the type's | ||
:c:member:`~PyTypeObject.tp_base`, plus any extra data needed | ||
by each instance. | ||
|
||
The correct way to set :c:member:`!tp_basicsize` is to use the | ||
``sizeof`` operator on the struct used to declare the instance layout. | ||
This struct must include the struct used to declare the base type. | ||
In other words, :c:member:`!tp_basicsize` must be greater than or equal | ||
to the base's :c:member:`!tp_basicsize`. | ||
|
||
Since every type is a subtype of :py:type:`object`, this struct must | ||
include :c:type:`PyObject` or :c:type:`PyVarObject` (depending on | ||
whether :c:member:`~PyVarObject.ob_size` should be included). These are | ||
usually defined by the macro :c:macro:`PyObject_HEAD` or | ||
:c:macro:`PyObject_VAR_HEAD`, respectively. | ||
|
||
The basic size does not include the GC header size, as that header is not | ||
ZeroIntensity marked this conversation as resolved.
Show resolved
Hide resolved
|
||
part of :c:macro:`PyObject_HEAD`. | ||
|
||
For cases where struct used to declare the base type is unknown, | ||
see :c:member:`PyType_Spec.basicsize` and :c:func:`PyType_FromMetaclass`. | ||
|
||
Notes about alignment: | ||
|
||
- :c:member:`!tp_basicsize` must be a multiple of ``_Alignof(PyObject)``. | ||
When using ``sizeof`` on a ``struct`` that includes | ||
:c:macro:`PyObject_HEAD`, as recommended, the compiler ensures this. | ||
When not using a C ``struct``, or when using compiler | ||
extensions like ``__attribute__((packed))``, it is up to you. | ||
- If the variable items require a particular alignment, | ||
:c:member:`!tp_basicsize` and :c:member:`!tp_itemsize` must each be a | ||
multiple of that alignment. | ||
For example, if a type's variable part stores a ``double``, it is | ||
your responsibility that both fields are a multiple of | ||
``_Alignof(double)``. | ||
|
||
**Inheritance:** | ||
|
||
These fields are inherited separately by subtypes. If the base type has a | ||
non-zero :c:member:`~PyTypeObject.tp_itemsize`, it is generally not safe to set | ||
These fields are inherited separately by subtypes. | ||
(That is, if the field is set to zero, :c:func:`PyType_Ready` will copy | ||
the value from the base type, indicating that the instances do not | ||
need additional storage.) | ||
|
||
If the base type has a non-zero :c:member:`~PyTypeObject.tp_itemsize`, it is generally not safe to set | ||
:c:member:`~PyTypeObject.tp_itemsize` to a different non-zero value in a subtype (though this | ||
depends on the implementation of the base type). | ||
|
||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.