# SOME DESCRIPTIVE TITLE.
# Copyright (C) 2001 Python Software Foundation
# This file is distributed under the same license as the Python package.
# FIRST AUTHOR , YEAR.
#
# Translators:
# python-doc bot, 2025
#
msgid ""
msgstr ""
"Project-Id-Version: Python 3.14\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-09-05 16:53+0200\n"
"PO-Revision-Date: 2025-09-16 00:00+0000\n"
"Last-Translator: python-doc bot, 2025\n"
"Language-Team: German (https://app.transifex.com/python-doc/teams/5390/de/)\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: ../../extending/newtypes_tutorial.rst:7
msgid "Defining Extension Types: Tutorial"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:14
msgid ""
"Python allows the writer of a C extension module to define new types that "
"can be manipulated from Python code, much like the built-in :class:`str` "
"and :class:`list` types. The code for all extension types follows a "
"pattern, but there are some details that you need to understand before you "
"can get started. This document is a gentle introduction to the topic."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:24
msgid "The Basics"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:26
msgid ""
"The :term:`CPython` runtime sees all Python objects as variables of type :c:"
"expr:`PyObject*`, which serves as a \"base type\" for all Python objects. "
"The :c:type:`PyObject` structure itself only contains the object's :term:"
"`reference count` and a pointer to the object's \"type object\". This is "
"where the action is; the type object determines which (C) functions get "
"called by the interpreter when, for instance, an attribute gets looked up on "
"an object, a method called, or it is multiplied by another object. These C "
"functions are called \"type methods\"."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:35
msgid ""
"So, if you want to define a new extension type, you need to create a new "
"type object."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:38
msgid ""
"This sort of thing can only be explained by example, so here's a minimal, "
"but complete, module that defines a new type named :class:`!Custom` inside a "
"C extension module :mod:`!custom`:"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:43
msgid ""
"What we're showing here is the traditional way of defining *static* "
"extension types. It should be adequate for most uses. The C API also "
"allows defining heap-allocated extension types using the :c:func:"
"`PyType_FromSpec` function, which isn't covered in this tutorial."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:48
msgid ""
"#define PY_SSIZE_T_CLEAN\n"
"#include \n"
"\n"
"typedef struct {\n"
" PyObject_HEAD\n"
" /* Type-specific fields go here. */\n"
"} CustomObject;\n"
"\n"
"static PyTypeObject CustomType = {\n"
" .ob_base = PyVarObject_HEAD_INIT(NULL, 0)\n"
" .tp_name = \"custom.Custom\",\n"
" .tp_doc = PyDoc_STR(\"Custom objects\"),\n"
" .tp_basicsize = sizeof(CustomObject),\n"
" .tp_itemsize = 0,\n"
" .tp_flags = Py_TPFLAGS_DEFAULT,\n"
" .tp_new = PyType_GenericNew,\n"
"};\n"
"\n"
"static int\n"
"custom_module_exec(PyObject *m)\n"
"{\n"
" if (PyType_Ready(&CustomType) < 0) {\n"
" return -1;\n"
" }\n"
"\n"
" if (PyModule_AddObjectRef(m, \"Custom\", (PyObject *) &CustomType) < 0) "
"{\n"
" return -1;\n"
" }\n"
"\n"
" return 0;\n"
"}\n"
"\n"
"static PyModuleDef_Slot custom_module_slots[] = {\n"
" {Py_mod_exec, custom_module_exec},\n"
" // Just use this while using static types\n"
" {Py_mod_multiple_interpreters, "
"Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED},\n"
" {0, NULL}\n"
"};\n"
"\n"
"static PyModuleDef custom_module = {\n"
" .m_base = PyModuleDef_HEAD_INIT,\n"
" .m_name = \"custom\",\n"
" .m_doc = \"Example module that creates an extension type.\",\n"
" .m_size = 0,\n"
" .m_slots = custom_module_slots,\n"
"};\n"
"\n"
"PyMODINIT_FUNC\n"
"PyInit_custom(void)\n"
"{\n"
" return PyModuleDef_Init(&custom_module);\n"
"}\n"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:50
msgid ""
"Now that's quite a bit to take in at once, but hopefully bits will seem "
"familiar from the previous chapter. This file defines three things:"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:53
msgid ""
"What a :class:`!Custom` **object** contains: this is the ``CustomObject`` "
"struct, which is allocated once for each :class:`!Custom` instance."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:55
msgid ""
"How the :class:`!Custom` **type** behaves: this is the ``CustomType`` "
"struct, which defines a set of flags and function pointers that the "
"interpreter inspects when specific operations are requested."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:58
msgid ""
"How to define and execute the :mod:`!custom` module: this is the "
"``PyInit_custom`` function and the associated ``custom_module`` struct for "
"defining the module, and the ``custom_module_exec`` function to set up a "
"fresh module object."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:63
msgid "The first bit is::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:65
msgid ""
"typedef struct {\n"
" PyObject_HEAD\n"
"} CustomObject;"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:69
msgid ""
"This is what a Custom object will contain. ``PyObject_HEAD`` is mandatory "
"at the start of each object struct and defines a field called ``ob_base`` of "
"type :c:type:`PyObject`, containing a pointer to a type object and a "
"reference count (these can be accessed using the macros :c:macro:`Py_TYPE` "
"and :c:macro:`Py_REFCNT` respectively). The reason for the macro is to "
"abstract away the layout and to enable additional fields in :ref:`debug "
"builds `."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:78
msgid ""
"There is no semicolon above after the :c:macro:`PyObject_HEAD` macro. Be "
"wary of adding one by accident: some compilers will complain."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:81
msgid ""
"Of course, objects generally store additional data besides the standard "
"``PyObject_HEAD`` boilerplate; for example, here is the definition for "
"standard Python floats::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:85
msgid ""
"typedef struct {\n"
" PyObject_HEAD\n"
" double ob_fval;\n"
"} PyFloatObject;"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:90
msgid "The second bit is the definition of the type object. ::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:92
msgid ""
"static PyTypeObject CustomType = {\n"
" .ob_base = PyVarObject_HEAD_INIT(NULL, 0)\n"
" .tp_name = \"custom.Custom\",\n"
" .tp_doc = PyDoc_STR(\"Custom objects\"),\n"
" .tp_basicsize = sizeof(CustomObject),\n"
" .tp_itemsize = 0,\n"
" .tp_flags = Py_TPFLAGS_DEFAULT,\n"
" .tp_new = PyType_GenericNew,\n"
"};"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:103
msgid ""
"We recommend using C99-style designated initializers as above, to avoid "
"listing all the :c:type:`PyTypeObject` fields that you don't care about and "
"also to avoid caring about the fields' declaration order."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:107
msgid ""
"The actual definition of :c:type:`PyTypeObject` in :file:`object.h` has many "
"more :ref:`fields ` than the definition above. The remaining "
"fields will be filled with zeros by the C compiler, and it's common practice "
"to not specify them explicitly unless you need them."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:112
msgid "We're going to pick it apart, one field at a time::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:114
msgid ".ob_base = PyVarObject_HEAD_INIT(NULL, 0)"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:116
msgid ""
"This line is mandatory boilerplate to initialize the ``ob_base`` field "
"mentioned above. ::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:119
msgid ".tp_name = \"custom.Custom\","
msgstr ""
#: ../../extending/newtypes_tutorial.rst:121
msgid ""
"The name of our type. This will appear in the default textual "
"representation of our objects and in some error messages, for example:"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:124
msgid ""
">>> \"\" + custom.Custom()\n"
"Traceback (most recent call last):\n"
" File \"\", line 1, in \n"
"TypeError: can only concatenate str (not \"custom.Custom\") to str"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:131
msgid ""
"Note that the name is a dotted name that includes both the module name and "
"the name of the type within the module. The module in this case is :mod:`!"
"custom` and the type is :class:`!Custom`, so we set the type name to :class:"
"`!custom.Custom`. Using the real dotted import path is important to make "
"your type compatible with the :mod:`pydoc` and :mod:`pickle` modules. ::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:137
msgid ""
".tp_basicsize = sizeof(CustomObject),\n"
".tp_itemsize = 0,"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:140
msgid ""
"This is so that Python knows how much memory to allocate when creating new :"
"class:`!Custom` instances. :c:member:`~PyTypeObject.tp_itemsize` is only "
"used for variable-sized objects and should otherwise be zero."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:146
msgid ""
"If you want your type to be subclassable from Python, and your type has the "
"same :c:member:`~PyTypeObject.tp_basicsize` as its base type, you may have "
"problems with multiple inheritance. A Python subclass of your type will "
"have to list your type first in its :attr:`~type.__bases__`, or else it will "
"not be able to call your type's :meth:`~object.__new__` method without "
"getting an error. You can avoid this problem by ensuring that your type has "
"a larger value for :c:member:`~PyTypeObject.tp_basicsize` than its base type "
"does. Most of the time, this will be true anyway, because either your base "
"type will be :class:`object`, or else you will be adding data members to "
"your base type, and therefore increasing its size."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:156
msgid "We set the class flags to :c:macro:`Py_TPFLAGS_DEFAULT`. ::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:158
msgid ".tp_flags = Py_TPFLAGS_DEFAULT,"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:160
msgid ""
"All types should include this constant in their flags. It enables all of "
"the members defined until at least Python 3.3. If you need further members, "
"you will need to OR the corresponding flags."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:164
msgid ""
"We provide a doc string for the type in :c:member:`~PyTypeObject.tp_doc`. ::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:166
msgid ".tp_doc = PyDoc_STR(\"Custom objects\"),"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:168
msgid ""
"To enable object creation, we have to provide a :c:member:`~PyTypeObject."
"tp_new` handler. This is the equivalent of the Python method :meth:`~object."
"__new__`, but has to be specified explicitly. In this case, we can just use "
"the default implementation provided by the API function :c:func:"
"`PyType_GenericNew`. ::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:173
msgid ".tp_new = PyType_GenericNew,"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:175
msgid ""
"Everything else in the file should be familiar, except for some code in :c:"
"func:`!custom_module_exec`::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:178
msgid ""
"if (PyType_Ready(&CustomType) < 0) {\n"
" return -1;\n"
"}"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:182
msgid ""
"This initializes the :class:`!Custom` type, filling in a number of members "
"to the appropriate default values, including :c:member:`~PyObject.ob_type` "
"that we initially set to ``NULL``. ::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:186
msgid ""
"if (PyModule_AddObjectRef(m, \"Custom\", (PyObject *) &CustomType) < 0) {\n"
" return -1;\n"
"}"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:190
msgid ""
"This adds the type to the module dictionary. This allows us to create :"
"class:`!Custom` instances by calling the :class:`!Custom` class:"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:193
msgid ""
">>> import custom\n"
">>> mycustom = custom.Custom()"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:198
msgid ""
"That's it! All that remains is to build it; put the above code in a file "
"called :file:`custom.c`,"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:201
msgid ""
"[build-system]\n"
"requires = [\"setuptools\"]\n"
"build-backend = \"setuptools.build_meta\"\n"
"\n"
"[project]\n"
"name = \"custom\"\n"
"version = \"1\"\n"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:203
msgid "in a file called :file:`pyproject.toml`, and"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:205
msgid ""
"from setuptools import Extension, setup\n"
"setup(ext_modules=[Extension(\"custom\", [\"custom.c\"])])"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:210
msgid "in a file called :file:`setup.py`; then typing"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:212
#: ../../extending/newtypes_tutorial.rst:550
msgid "$ python -m pip install ."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:216
msgid ""
"in a shell should produce a file :file:`custom.so` in a subdirectory and "
"install it; now fire up Python --- you should be able to ``import custom`` "
"and play around with ``Custom`` objects."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:220
msgid "That wasn't so hard, was it?"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:222
msgid ""
"Of course, the current Custom type is pretty uninteresting. It has no data "
"and doesn't do anything. It can't even be subclassed."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:227
msgid "Adding data and methods to the Basic example"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:229
msgid ""
"Let's extend the basic example to add some data and methods. Let's also "
"make the type usable as a base class. We'll create a new module, :mod:`!"
"custom2` that adds these capabilities:"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:233
msgid ""
"#define PY_SSIZE_T_CLEAN\n"
"#include \n"
"#include /* for offsetof() */\n"
"\n"
"typedef struct {\n"
" PyObject_HEAD\n"
" PyObject *first; /* first name */\n"
" PyObject *last; /* last name */\n"
" int number;\n"
"} CustomObject;\n"
"\n"
"static void\n"
"Custom_dealloc(PyObject *op)\n"
"{\n"
" CustomObject *self = (CustomObject *) op;\n"
" Py_XDECREF(self->first);\n"
" Py_XDECREF(self->last);\n"
" Py_TYPE(self)->tp_free(self);\n"
"}\n"
"\n"
"static PyObject *\n"
"Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)\n"
"{\n"
" CustomObject *self;\n"
" self = (CustomObject *) type->tp_alloc(type, 0);\n"
" if (self != NULL) {\n"
" self->first = Py_GetConstant(Py_CONSTANT_EMPTY_STR);\n"
" if (self->first == NULL) {\n"
" Py_DECREF(self);\n"
" return NULL;\n"
" }\n"
" self->last = Py_GetConstant(Py_CONSTANT_EMPTY_STR);\n"
" if (self->last == NULL) {\n"
" Py_DECREF(self);\n"
" return NULL;\n"
" }\n"
" self->number = 0;\n"
" }\n"
" return (PyObject *) self;\n"
"}\n"
"\n"
"static int\n"
"Custom_init(PyObject *op, PyObject *args, PyObject *kwds)\n"
"{\n"
" CustomObject *self = (CustomObject *) op;\n"
" static char *kwlist[] = {\"first\", \"last\", \"number\", NULL};\n"
" PyObject *first = NULL, *last = NULL;\n"
"\n"
" if (!PyArg_ParseTupleAndKeywords(args, kwds, \"|OOi\", kwlist,\n"
" &first, &last,\n"
" &self->number))\n"
" return -1;\n"
"\n"
" if (first) {\n"
" Py_XSETREF(self->first, Py_NewRef(first));\n"
" }\n"
" if (last) {\n"
" Py_XSETREF(self->last, Py_NewRef(last));\n"
" }\n"
" return 0;\n"
"}\n"
"\n"
"static PyMemberDef Custom_members[] = {\n"
" {\"first\", Py_T_OBJECT_EX, offsetof(CustomObject, first), 0,\n"
" \"first name\"},\n"
" {\"last\", Py_T_OBJECT_EX, offsetof(CustomObject, last), 0,\n"
" \"last name\"},\n"
" {\"number\", Py_T_INT, offsetof(CustomObject, number), 0,\n"
" \"custom number\"},\n"
" {NULL} /* Sentinel */\n"
"};\n"
"\n"
"static PyObject *\n"
"Custom_name(PyObject *op, PyObject *Py_UNUSED(dummy))\n"
"{\n"
" CustomObject *self = (CustomObject *) op;\n"
" if (self->first == NULL) {\n"
" PyErr_SetString(PyExc_AttributeError, \"first\");\n"
" return NULL;\n"
" }\n"
" if (self->last == NULL) {\n"
" PyErr_SetString(PyExc_AttributeError, \"last\");\n"
" return NULL;\n"
" }\n"
" return PyUnicode_FromFormat(\"%S %S\", self->first, self->last);\n"
"}\n"
"\n"
"static PyMethodDef Custom_methods[] = {\n"
" {\"name\", Custom_name, METH_NOARGS,\n"
" \"Return the name, combining the first and last name\"\n"
" },\n"
" {NULL} /* Sentinel */\n"
"};\n"
"\n"
"static PyTypeObject CustomType = {\n"
" .ob_base = PyVarObject_HEAD_INIT(NULL, 0)\n"
" .tp_name = \"custom2.Custom\",\n"
" .tp_doc = PyDoc_STR(\"Custom objects\"),\n"
" .tp_basicsize = sizeof(CustomObject),\n"
" .tp_itemsize = 0,\n"
" .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,\n"
" .tp_new = Custom_new,\n"
" .tp_init = Custom_init,\n"
" .tp_dealloc = Custom_dealloc,\n"
" .tp_members = Custom_members,\n"
" .tp_methods = Custom_methods,\n"
"};\n"
"\n"
"static int\n"
"custom_module_exec(PyObject *m)\n"
"{\n"
" if (PyType_Ready(&CustomType) < 0) {\n"
" return -1;\n"
" }\n"
"\n"
" if (PyModule_AddObjectRef(m, \"Custom\", (PyObject *) &CustomType) < 0) "
"{\n"
" return -1;\n"
" }\n"
"\n"
" return 0;\n"
"}\n"
"\n"
"static PyModuleDef_Slot custom_module_slots[] = {\n"
" {Py_mod_exec, custom_module_exec},\n"
" {Py_mod_multiple_interpreters, "
"Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED},\n"
" {0, NULL}\n"
"};\n"
"\n"
"static PyModuleDef custom_module = {\n"
" .m_base = PyModuleDef_HEAD_INIT,\n"
" .m_name = \"custom2\",\n"
" .m_doc = \"Example module that creates an extension type.\",\n"
" .m_size = 0,\n"
" .m_slots = custom_module_slots,\n"
"};\n"
"\n"
"PyMODINIT_FUNC\n"
"PyInit_custom2(void)\n"
"{\n"
" return PyModuleDef_Init(&custom_module);\n"
"}\n"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:236
msgid "This version of the module has a number of changes."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:238
msgid ""
"The :class:`!Custom` type now has three data attributes in its C struct, "
"*first*, *last*, and *number*. The *first* and *last* variables are Python "
"strings containing first and last names. The *number* attribute is a C "
"integer."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:242
msgid "The object structure is updated accordingly::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:244
msgid ""
"typedef struct {\n"
" PyObject_HEAD\n"
" PyObject *first; /* first name */\n"
" PyObject *last; /* last name */\n"
" int number;\n"
"} CustomObject;"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:251
msgid ""
"Because we now have data to manage, we have to be more careful about object "
"allocation and deallocation. At a minimum, we need a deallocation method::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:254
msgid ""
"static void\n"
"Custom_dealloc(PyObject *op)\n"
"{\n"
" CustomObject *self = (CustomObject *) op;\n"
" Py_XDECREF(self->first);\n"
" Py_XDECREF(self->last);\n"
" Py_TYPE(self)->tp_free(self);\n"
"}"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:263
msgid "which is assigned to the :c:member:`~PyTypeObject.tp_dealloc` member::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:265
msgid ".tp_dealloc = Custom_dealloc,"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:267
msgid ""
"This method first clears the reference counts of the two Python attributes. :"
"c:func:`Py_XDECREF` correctly handles the case where its argument is "
"``NULL`` (which might happen here if ``tp_new`` failed midway). It then "
"calls the :c:member:`~PyTypeObject.tp_free` member of the object's type "
"(computed by ``Py_TYPE(self)``) to free the object's memory. Note that the "
"object's type might not be :class:`!CustomType`, because the object may be "
"an instance of a subclass."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:277
msgid ""
"The explicit cast to ``CustomObject *`` above is needed because we defined "
"``Custom_dealloc`` to take a ``PyObject *`` argument, as the ``tp_dealloc`` "
"function pointer expects to receive a ``PyObject *`` argument. By assigning "
"to the ``tp_dealloc`` slot of a type, we declare that it can only be called "
"with instances of our ``CustomObject`` class, so the cast to ``(CustomObject "
"*)`` is safe. This is object-oriented polymorphism, in C!"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:285
msgid ""
"In existing code, or in previous versions of this tutorial, you might see "
"similar functions take a pointer to the subtype object structure "
"(``CustomObject*``) directly, like this::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:289
msgid ""
"Custom_dealloc(CustomObject *self)\n"
"{\n"
" Py_XDECREF(self->first);\n"
" Py_XDECREF(self->last);\n"
" Py_TYPE(self)->tp_free((PyObject *) self);\n"
"}\n"
"...\n"
".tp_dealloc = (destructor) Custom_dealloc,"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:298
msgid ""
"This does the same thing on all architectures that CPython supports, but "
"according to the C standard, it invokes undefined behavior."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:302
msgid ""
"We want to make sure that the first and last names are initialized to empty "
"strings, so we provide a ``tp_new`` implementation::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:305
msgid ""
"static PyObject *\n"
"Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)\n"
"{\n"
" CustomObject *self;\n"
" self = (CustomObject *) type->tp_alloc(type, 0);\n"
" if (self != NULL) {\n"
" self->first = PyUnicode_FromString(\"\");\n"
" if (self->first == NULL) {\n"
" Py_DECREF(self);\n"
" return NULL;\n"
" }\n"
" self->last = PyUnicode_FromString(\"\");\n"
" if (self->last == NULL) {\n"
" Py_DECREF(self);\n"
" return NULL;\n"
" }\n"
" self->number = 0;\n"
" }\n"
" return (PyObject *) self;\n"
"}"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:326
msgid "and install it in the :c:member:`~PyTypeObject.tp_new` member::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:328
msgid ".tp_new = Custom_new,"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:330
msgid ""
"The ``tp_new`` handler is responsible for creating (as opposed to "
"initializing) objects of the type. It is exposed in Python as the :meth:"
"`~object.__new__` method. It is not required to define a ``tp_new`` member, "
"and indeed many extension types will simply reuse :c:func:"
"`PyType_GenericNew` as done in the first version of the :class:`!Custom` "
"type above. In this case, we use the ``tp_new`` handler to initialize the "
"``first`` and ``last`` attributes to non-``NULL`` default values."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:338
msgid ""
"``tp_new`` is passed the type being instantiated (not necessarily "
"``CustomType``, if a subclass is instantiated) and any arguments passed when "
"the type was called, and is expected to return the instance created. "
"``tp_new`` handlers always accept positional and keyword arguments, but they "
"often ignore the arguments, leaving the argument handling to initializer (a."
"k.a. ``tp_init`` in C or ``__init__`` in Python) methods."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:346
msgid ""
"``tp_new`` shouldn't call ``tp_init`` explicitly, as the interpreter will do "
"it itself."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:349
msgid ""
"The ``tp_new`` implementation calls the :c:member:`~PyTypeObject.tp_alloc` "
"slot to allocate memory::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:352
msgid "self = (CustomObject *) type->tp_alloc(type, 0);"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:354
msgid ""
"Since memory allocation may fail, we must check the :c:member:`~PyTypeObject."
"tp_alloc` result against ``NULL`` before proceeding."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:358
msgid ""
"We didn't fill the :c:member:`~PyTypeObject.tp_alloc` slot ourselves. "
"Rather :c:func:`PyType_Ready` fills it for us by inheriting it from our base "
"class, which is :class:`object` by default. Most types use the default "
"allocation strategy."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:364
msgid ""
"If you are creating a co-operative :c:member:`~PyTypeObject.tp_new` (one "
"that calls a base type's :c:member:`~PyTypeObject.tp_new` or :meth:`~object."
"__new__`), you must *not* try to determine what method to call using method "
"resolution order at runtime. Always statically determine what type you are "
"going to call, and call its :c:member:`~PyTypeObject.tp_new` directly, or "
"via ``type->tp_base->tp_new``. If you do not do this, Python subclasses of "
"your type that also inherit from other Python-defined classes may not work "
"correctly. (Specifically, you may not be able to create instances of such "
"subclasses without getting a :exc:`TypeError`.)"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:374
msgid ""
"We also define an initialization function which accepts arguments to provide "
"initial values for our instance::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:377
msgid ""
"static int\n"
"Custom_init(PyObject *op, PyObject *args, PyObject *kwds)\n"
"{\n"
" CustomObject *self = (CustomObject *) op;\n"
" static char *kwlist[] = {\"first\", \"last\", \"number\", NULL};\n"
" PyObject *first = NULL, *last = NULL, *tmp;\n"
"\n"
" if (!PyArg_ParseTupleAndKeywords(args, kwds, \"|OOi\", kwlist,\n"
" &first, &last,\n"
" &self->number))\n"
" return -1;\n"
"\n"
" if (first) {\n"
" tmp = self->first;\n"
" Py_INCREF(first);\n"
" self->first = first;\n"
" Py_XDECREF(tmp);\n"
" }\n"
" if (last) {\n"
" tmp = self->last;\n"
" Py_INCREF(last);\n"
" self->last = last;\n"
" Py_XDECREF(tmp);\n"
" }\n"
" return 0;\n"
"}"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:404
msgid "by filling the :c:member:`~PyTypeObject.tp_init` slot. ::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:406
msgid ".tp_init = Custom_init,"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:408
msgid ""
"The :c:member:`~PyTypeObject.tp_init` slot is exposed in Python as the :meth:"
"`~object.__init__` method. It is used to initialize an object after it's "
"created. Initializers always accept positional and keyword arguments, and "
"they should return either ``0`` on success or ``-1`` on error."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:413
msgid ""
"Unlike the ``tp_new`` handler, there is no guarantee that ``tp_init`` is "
"called at all (for example, the :mod:`pickle` module by default doesn't "
"call :meth:`~object.__init__` on unpickled instances). It can also be "
"called multiple times. Anyone can call the :meth:`!__init__` method on our "
"objects. For this reason, we have to be extra careful when assigning the "
"new attribute values. We might be tempted, for example to assign the "
"``first`` member like this::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:421
msgid ""
"if (first) {\n"
" Py_XDECREF(self->first);\n"
" Py_INCREF(first);\n"
" self->first = first;\n"
"}"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:427
msgid ""
"But this would be risky. Our type doesn't restrict the type of the "
"``first`` member, so it could be any kind of object. It could have a "
"destructor that causes code to be executed that tries to access the "
"``first`` member; or that destructor could detach the :term:`thread state "
"` and let arbitrary code run in other threads that "
"accesses and modifies our object."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:434
msgid ""
"To be paranoid and protect ourselves against this possibility, we almost "
"always reassign members before decrementing their reference counts. When "
"don't we have to do this?"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:438
msgid "when we absolutely know that the reference count is greater than 1;"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:440
msgid ""
"when we know that deallocation of the object [#]_ will neither detach the :"
"term:`thread state ` nor cause any calls back into "
"our type's code;"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:443
msgid ""
"when decrementing a reference count in a :c:member:`~PyTypeObject."
"tp_dealloc` handler on a type which doesn't support cyclic garbage "
"collection [#]_."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:446
msgid ""
"We want to expose our instance variables as attributes. There are a number "
"of ways to do that. The simplest way is to define member definitions::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:449
msgid ""
"static PyMemberDef Custom_members[] = {\n"
" {\"first\", Py_T_OBJECT_EX, offsetof(CustomObject, first), 0,\n"
" \"first name\"},\n"
" {\"last\", Py_T_OBJECT_EX, offsetof(CustomObject, last), 0,\n"
" \"last name\"},\n"
" {\"number\", Py_T_INT, offsetof(CustomObject, number), 0,\n"
" \"custom number\"},\n"
" {NULL} /* Sentinel */\n"
"};"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:459
msgid ""
"and put the definitions in the :c:member:`~PyTypeObject.tp_members` slot::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:461
msgid ".tp_members = Custom_members,"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:463
msgid ""
"Each member definition has a member name, type, offset, access flags and "
"documentation string. See the :ref:`Generic-Attribute-Management` section "
"below for details."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:467
msgid ""
"A disadvantage of this approach is that it doesn't provide a way to restrict "
"the types of objects that can be assigned to the Python attributes. We "
"expect the first and last names to be strings, but any Python objects can be "
"assigned. Further, the attributes can be deleted, setting the C pointers to "
"``NULL``. Even though we can make sure the members are initialized to non-"
"``NULL`` values, the members can be set to ``NULL`` if the attributes are "
"deleted."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:474
msgid ""
"We define a single method, :meth:`!Custom.name`, that outputs the objects "
"name as the concatenation of the first and last names. ::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:477
msgid ""
"static PyObject *\n"
"Custom_name(PyObject *op, PyObject *Py_UNUSED(dummy))\n"
"{\n"
" CustomObject *self = (CustomObject *) op;\n"
" if (self->first == NULL) {\n"
" PyErr_SetString(PyExc_AttributeError, \"first\");\n"
" return NULL;\n"
" }\n"
" if (self->last == NULL) {\n"
" PyErr_SetString(PyExc_AttributeError, \"last\");\n"
" return NULL;\n"
" }\n"
" return PyUnicode_FromFormat(\"%S %S\", self->first, self->last);\n"
"}"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:492
msgid ""
"The method is implemented as a C function that takes a :class:`!Custom` (or :"
"class:`!Custom` subclass) instance as the first argument. Methods always "
"take an instance as the first argument. Methods often take positional and "
"keyword arguments as well, but in this case we don't take any and don't need "
"to accept a positional argument tuple or keyword argument dictionary. This "
"method is equivalent to the Python method:"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:499
msgid ""
"def name(self):\n"
" return \"%s %s\" % (self.first, self.last)"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:504
msgid ""
"Note that we have to check for the possibility that our :attr:`!first` and :"
"attr:`!last` members are ``NULL``. This is because they can be deleted, in "
"which case they are set to ``NULL``. It would be better to prevent deletion "
"of these attributes and to restrict the attribute values to be strings. "
"We'll see how to do that in the next section."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:510
msgid ""
"Now that we've defined the method, we need to create an array of method "
"definitions::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:513
msgid ""
"static PyMethodDef Custom_methods[] = {\n"
" {\"name\", Custom_name, METH_NOARGS,\n"
" \"Return the name, combining the first and last name\"\n"
" },\n"
" {NULL} /* Sentinel */\n"
"};"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:520
msgid ""
"(note that we used the :c:macro:`METH_NOARGS` flag to indicate that the "
"method is expecting no arguments other than *self*)"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:523
msgid "and assign it to the :c:member:`~PyTypeObject.tp_methods` slot::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:525
msgid ".tp_methods = Custom_methods,"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:527
msgid ""
"Finally, we'll make our type usable as a base class for subclassing. We've "
"written our methods carefully so far so that they don't make any assumptions "
"about the type of the object being created or used, so all we need to do is "
"to add the :c:macro:`Py_TPFLAGS_BASETYPE` to our class flag definition::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:532
msgid ".tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:534
msgid ""
"We rename :c:func:`!PyInit_custom` to :c:func:`!PyInit_custom2`, update the "
"module name in the :c:type:`PyModuleDef` struct, and update the full class "
"name in the :c:type:`PyTypeObject` struct."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:538
msgid "Finally, we update our :file:`setup.py` file to include the new module,"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:540
msgid ""
"from setuptools import Extension, setup\n"
"setup(ext_modules=[\n"
" Extension(\"custom\", [\"custom.c\"]),\n"
" Extension(\"custom2\", [\"custom2.c\"]),\n"
"])"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:548
msgid "and then we re-install so that we can ``import custom2``:"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:555
msgid "Providing finer control over data attributes"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:557
msgid ""
"In this section, we'll provide finer control over how the :attr:`!first` "
"and :attr:`!last` attributes are set in the :class:`!Custom` example. In the "
"previous version of our module, the instance variables :attr:`!first` and :"
"attr:`!last` could be set to non-string values or even deleted. We want to "
"make sure that these attributes always contain strings."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:563
msgid ""
"#define PY_SSIZE_T_CLEAN\n"
"#include \n"
"#include /* for offsetof() */\n"
"\n"
"typedef struct {\n"
" PyObject_HEAD\n"
" PyObject *first; /* first name */\n"
" PyObject *last; /* last name */\n"
" int number;\n"
"} CustomObject;\n"
"\n"
"static void\n"
"Custom_dealloc(PyObject *op)\n"
"{\n"
" CustomObject *self = (CustomObject *) op;\n"
" Py_XDECREF(self->first);\n"
" Py_XDECREF(self->last);\n"
" Py_TYPE(self)->tp_free(self);\n"
"}\n"
"\n"
"static PyObject *\n"
"Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)\n"
"{\n"
" CustomObject *self;\n"
" self = (CustomObject *) type->tp_alloc(type, 0);\n"
" if (self != NULL) {\n"
" self->first = Py_GetConstant(Py_CONSTANT_EMPTY_STR);\n"
" if (self->first == NULL) {\n"
" Py_DECREF(self);\n"
" return NULL;\n"
" }\n"
" self->last = Py_GetConstant(Py_CONSTANT_EMPTY_STR);\n"
" if (self->last == NULL) {\n"
" Py_DECREF(self);\n"
" return NULL;\n"
" }\n"
" self->number = 0;\n"
" }\n"
" return (PyObject *) self;\n"
"}\n"
"\n"
"static int\n"
"Custom_init(PyObject *op, PyObject *args, PyObject *kwds)\n"
"{\n"
" CustomObject *self = (CustomObject *) op;\n"
" static char *kwlist[] = {\"first\", \"last\", \"number\", NULL};\n"
" PyObject *first = NULL, *last = NULL;\n"
"\n"
" if (!PyArg_ParseTupleAndKeywords(args, kwds, \"|UUi\", kwlist,\n"
" &first, &last,\n"
" &self->number))\n"
" return -1;\n"
"\n"
" if (first) {\n"
" Py_SETREF(self->first, Py_NewRef(first));\n"
" }\n"
" if (last) {\n"
" Py_SETREF(self->last, Py_NewRef(last));\n"
" }\n"
" return 0;\n"
"}\n"
"\n"
"static PyMemberDef Custom_members[] = {\n"
" {\"number\", Py_T_INT, offsetof(CustomObject, number), 0,\n"
" \"custom number\"},\n"
" {NULL} /* Sentinel */\n"
"};\n"
"\n"
"static PyObject *\n"
"Custom_getfirst(PyObject *op, void *closure)\n"
"{\n"
" CustomObject *self = (CustomObject *) op;\n"
" return Py_NewRef(self->first);\n"
"}\n"
"\n"
"static int\n"
"Custom_setfirst(PyObject *op, PyObject *value, void *closure)\n"
"{\n"
" CustomObject *self = (CustomObject *) op;\n"
" if (value == NULL) {\n"
" PyErr_SetString(PyExc_TypeError, \"Cannot delete the first "
"attribute\");\n"
" return -1;\n"
" }\n"
" if (!PyUnicode_Check(value)) {\n"
" PyErr_SetString(PyExc_TypeError,\n"
" \"The first attribute value must be a string\");\n"
" return -1;\n"
" }\n"
" Py_SETREF(self->first, Py_NewRef(value));\n"
" return 0;\n"
"}\n"
"\n"
"static PyObject *\n"
"Custom_getlast(PyObject *op, void *closure)\n"
"{\n"
" CustomObject *self = (CustomObject *) op;\n"
" return Py_NewRef(self->last);\n"
"}\n"
"\n"
"static int\n"
"Custom_setlast(PyObject *op, PyObject *value, void *closure)\n"
"{\n"
" CustomObject *self = (CustomObject *) op;\n"
" if (value == NULL) {\n"
" PyErr_SetString(PyExc_TypeError, \"Cannot delete the last "
"attribute\");\n"
" return -1;\n"
" }\n"
" if (!PyUnicode_Check(value)) {\n"
" PyErr_SetString(PyExc_TypeError,\n"
" \"The last attribute value must be a string\");\n"
" return -1;\n"
" }\n"
" Py_SETREF(self->last, Py_NewRef(value));\n"
" return 0;\n"
"}\n"
"\n"
"static PyGetSetDef Custom_getsetters[] = {\n"
" {\"first\", Custom_getfirst, Custom_setfirst,\n"
" \"first name\", NULL},\n"
" {\"last\", Custom_getlast, Custom_setlast,\n"
" \"last name\", NULL},\n"
" {NULL} /* Sentinel */\n"
"};\n"
"\n"
"static PyObject *\n"
"Custom_name(PyObject *op, PyObject *Py_UNUSED(dummy))\n"
"{\n"
" CustomObject *self = (CustomObject *) op;\n"
" return PyUnicode_FromFormat(\"%S %S\", self->first, self->last);\n"
"}\n"
"\n"
"static PyMethodDef Custom_methods[] = {\n"
" {\"name\", Custom_name, METH_NOARGS,\n"
" \"Return the name, combining the first and last name\"\n"
" },\n"
" {NULL} /* Sentinel */\n"
"};\n"
"\n"
"static PyTypeObject CustomType = {\n"
" .ob_base = PyVarObject_HEAD_INIT(NULL, 0)\n"
" .tp_name = \"custom3.Custom\",\n"
" .tp_doc = PyDoc_STR(\"Custom objects\"),\n"
" .tp_basicsize = sizeof(CustomObject),\n"
" .tp_itemsize = 0,\n"
" .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,\n"
" .tp_new = Custom_new,\n"
" .tp_init = Custom_init,\n"
" .tp_dealloc = Custom_dealloc,\n"
" .tp_members = Custom_members,\n"
" .tp_methods = Custom_methods,\n"
" .tp_getset = Custom_getsetters,\n"
"};\n"
"\n"
"static int\n"
"custom_module_exec(PyObject *m)\n"
"{\n"
" if (PyType_Ready(&CustomType) < 0) {\n"
" return -1;\n"
" }\n"
"\n"
" if (PyModule_AddObjectRef(m, \"Custom\", (PyObject *) &CustomType) < 0) "
"{\n"
" return -1;\n"
" }\n"
"\n"
" return 0;\n"
"}\n"
"\n"
"static PyModuleDef_Slot custom_module_slots[] = {\n"
" {Py_mod_exec, custom_module_exec},\n"
" {Py_mod_multiple_interpreters, "
"Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED},\n"
" {0, NULL}\n"
"};\n"
"\n"
"static PyModuleDef custom_module = {\n"
" .m_base = PyModuleDef_HEAD_INIT,\n"
" .m_name = \"custom3\",\n"
" .m_doc = \"Example module that creates an extension type.\",\n"
" .m_size = 0,\n"
" .m_slots = custom_module_slots,\n"
"};\n"
"\n"
"PyMODINIT_FUNC\n"
"PyInit_custom3(void)\n"
"{\n"
" return PyModuleDef_Init(&custom_module);\n"
"}\n"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:566
msgid ""
"To provide greater control, over the :attr:`!first` and :attr:`!last` "
"attributes, we'll use custom getter and setter functions. Here are the "
"functions for getting and setting the :attr:`!first` attribute::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:570
msgid ""
"static PyObject *\n"
"Custom_getfirst(PyObject *op, void *closure)\n"
"{\n"
" CustomObject *self = (CustomObject *) op;\n"
" Py_INCREF(self->first);\n"
" return self->first;\n"
"}\n"
"\n"
"static int\n"
"Custom_setfirst(PyObject *op, PyObject *value, void *closure)\n"
"{\n"
" CustomObject *self = (CustomObject *) op;\n"
" PyObject *tmp;\n"
" if (value == NULL) {\n"
" PyErr_SetString(PyExc_TypeError, \"Cannot delete the first "
"attribute\");\n"
" return -1;\n"
" }\n"
" if (!PyUnicode_Check(value)) {\n"
" PyErr_SetString(PyExc_TypeError,\n"
" \"The first attribute value must be a string\");\n"
" return -1;\n"
" }\n"
" tmp = self->first;\n"
" Py_INCREF(value);\n"
" self->first = value;\n"
" Py_DECREF(tmp);\n"
" return 0;\n"
"}"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:599
msgid ""
"The getter function is passed a :class:`!Custom` object and a \"closure\", "
"which is a void pointer. In this case, the closure is ignored. (The "
"closure supports an advanced usage in which definition data is passed to the "
"getter and setter. This could, for example, be used to allow a single set of "
"getter and setter functions that decide the attribute to get or set based on "
"data in the closure.)"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:605
msgid ""
"The setter function is passed the :class:`!Custom` object, the new value, "
"and the closure. The new value may be ``NULL``, in which case the attribute "
"is being deleted. In our setter, we raise an error if the attribute is "
"deleted or if its new value is not a string."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:610
msgid "We create an array of :c:type:`PyGetSetDef` structures::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:612
msgid ""
"static PyGetSetDef Custom_getsetters[] = {\n"
" {\"first\", Custom_getfirst, Custom_setfirst,\n"
" \"first name\", NULL},\n"
" {\"last\", Custom_getlast, Custom_setlast,\n"
" \"last name\", NULL},\n"
" {NULL} /* Sentinel */\n"
"};"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:620
msgid "and register it in the :c:member:`~PyTypeObject.tp_getset` slot::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:622
msgid ".tp_getset = Custom_getsetters,"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:624
msgid ""
"The last item in a :c:type:`PyGetSetDef` structure is the \"closure\" "
"mentioned above. In this case, we aren't using a closure, so we just pass "
"``NULL``."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:627
msgid "We also remove the member definitions for these attributes::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:629
msgid ""
"static PyMemberDef Custom_members[] = {\n"
" {\"number\", Py_T_INT, offsetof(CustomObject, number), 0,\n"
" \"custom number\"},\n"
" {NULL} /* Sentinel */\n"
"};"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:635
msgid ""
"We also need to update the :c:member:`~PyTypeObject.tp_init` handler to only "
"allow strings [#]_ to be passed::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:638
msgid ""
"static int\n"
"Custom_init(PyObject *op, PyObject *args, PyObject *kwds)\n"
"{\n"
" CustomObject *self = (CustomObject *) op;\n"
" static char *kwlist[] = {\"first\", \"last\", \"number\", NULL};\n"
" PyObject *first = NULL, *last = NULL, *tmp;\n"
"\n"
" if (!PyArg_ParseTupleAndKeywords(args, kwds, \"|UUi\", kwlist,\n"
" &first, &last,\n"
" &self->number))\n"
" return -1;\n"
"\n"
" if (first) {\n"
" tmp = self->first;\n"
" Py_INCREF(first);\n"
" self->first = first;\n"
" Py_DECREF(tmp);\n"
" }\n"
" if (last) {\n"
" tmp = self->last;\n"
" Py_INCREF(last);\n"
" self->last = last;\n"
" Py_DECREF(tmp);\n"
" }\n"
" return 0;\n"
"}"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:665
msgid ""
"With these changes, we can assure that the ``first`` and ``last`` members "
"are never ``NULL`` so we can remove checks for ``NULL`` values in almost all "
"cases. This means that most of the :c:func:`Py_XDECREF` calls can be "
"converted to :c:func:`Py_DECREF` calls. The only place we can't change "
"these calls is in the ``tp_dealloc`` implementation, where there is the "
"possibility that the initialization of these members failed in ``tp_new``."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:672
msgid ""
"We also rename the module initialization function and module name in the "
"initialization function, as we did before, and we add an extra definition to "
"the :file:`setup.py` file."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:678
msgid "Supporting cyclic garbage collection"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:680
msgid ""
"Python has a :term:`cyclic garbage collector (GC) ` that "
"can identify unneeded objects even when their reference counts are not zero. "
"This can happen when objects are involved in cycles. For example, consider:"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:684
msgid ""
">>> l = []\n"
">>> l.append(l)\n"
">>> del l"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:690
msgid ""
"In this example, we create a list that contains itself. When we delete it, "
"it still has a reference from itself. Its reference count doesn't drop to "
"zero. Fortunately, Python's cyclic garbage collector will eventually figure "
"out that the list is garbage and free it."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:695
msgid ""
"In the second version of the :class:`!Custom` example, we allowed any kind "
"of object to be stored in the :attr:`!first` or :attr:`!last` attributes "
"[#]_. Besides, in the second and third versions, we allowed subclassing :"
"class:`!Custom`, and subclasses may add arbitrary attributes. For any of "
"those two reasons, :class:`!Custom` objects can participate in cycles:"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:701
msgid ""
">>> import custom3\n"
">>> class Derived(custom3.Custom): pass\n"
"...\n"
">>> n = Derived()\n"
">>> n.some_attribute = n"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:709
msgid ""
"To allow a :class:`!Custom` instance participating in a reference cycle to "
"be properly detected and collected by the cyclic GC, our :class:`!Custom` "
"type needs to fill two additional slots and to enable a flag that enables "
"these slots:"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:713
msgid ""
"#define PY_SSIZE_T_CLEAN\n"
"#include \n"
"#include /* for offsetof() */\n"
"\n"
"typedef struct {\n"
" PyObject_HEAD\n"
" PyObject *first; /* first name */\n"
" PyObject *last; /* last name */\n"
" int number;\n"
"} CustomObject;\n"
"\n"
"static int\n"
"Custom_traverse(PyObject *op, visitproc visit, void *arg)\n"
"{\n"
" CustomObject *self = (CustomObject *) op;\n"
" Py_VISIT(self->first);\n"
" Py_VISIT(self->last);\n"
" return 0;\n"
"}\n"
"\n"
"static int\n"
"Custom_clear(PyObject *op)\n"
"{\n"
" CustomObject *self = (CustomObject *) op;\n"
" Py_CLEAR(self->first);\n"
" Py_CLEAR(self->last);\n"
" return 0;\n"
"}\n"
"\n"
"static void\n"
"Custom_dealloc(PyObject *op)\n"
"{\n"
" PyObject_GC_UnTrack(op);\n"
" (void)Custom_clear(op);\n"
" Py_TYPE(op)->tp_free(op);\n"
"}\n"
"\n"
"static PyObject *\n"
"Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)\n"
"{\n"
" CustomObject *self;\n"
" self = (CustomObject *) type->tp_alloc(type, 0);\n"
" if (self != NULL) {\n"
" self->first = Py_GetConstant(Py_CONSTANT_EMPTY_STR);\n"
" if (self->first == NULL) {\n"
" Py_DECREF(self);\n"
" return NULL;\n"
" }\n"
" self->last = Py_GetConstant(Py_CONSTANT_EMPTY_STR);\n"
" if (self->last == NULL) {\n"
" Py_DECREF(self);\n"
" return NULL;\n"
" }\n"
" self->number = 0;\n"
" }\n"
" return (PyObject *) self;\n"
"}\n"
"\n"
"static int\n"
"Custom_init(PyObject *op, PyObject *args, PyObject *kwds)\n"
"{\n"
" CustomObject *self = (CustomObject *) op;\n"
" static char *kwlist[] = {\"first\", \"last\", \"number\", NULL};\n"
" PyObject *first = NULL, *last = NULL;\n"
"\n"
" if (!PyArg_ParseTupleAndKeywords(args, kwds, \"|UUi\", kwlist,\n"
" &first, &last,\n"
" &self->number))\n"
" return -1;\n"
"\n"
" if (first) {\n"
" Py_SETREF(self->first, Py_NewRef(first));\n"
" }\n"
" if (last) {\n"
" Py_SETREF(self->last, Py_NewRef(last));\n"
" }\n"
" return 0;\n"
"}\n"
"\n"
"static PyMemberDef Custom_members[] = {\n"
" {\"number\", Py_T_INT, offsetof(CustomObject, number), 0,\n"
" \"custom number\"},\n"
" {NULL} /* Sentinel */\n"
"};\n"
"\n"
"static PyObject *\n"
"Custom_getfirst(PyObject *op, void *closure)\n"
"{\n"
" CustomObject *self = (CustomObject *) op;\n"
" return Py_NewRef(self->first);\n"
"}\n"
"\n"
"static int\n"
"Custom_setfirst(PyObject *op, PyObject *value, void *closure)\n"
"{\n"
" CustomObject *self = (CustomObject *) op;\n"
" if (value == NULL) {\n"
" PyErr_SetString(PyExc_TypeError, \"Cannot delete the first "
"attribute\");\n"
" return -1;\n"
" }\n"
" if (!PyUnicode_Check(value)) {\n"
" PyErr_SetString(PyExc_TypeError,\n"
" \"The first attribute value must be a string\");\n"
" return -1;\n"
" }\n"
" Py_XSETREF(self->first, Py_NewRef(value));\n"
" return 0;\n"
"}\n"
"\n"
"static PyObject *\n"
"Custom_getlast(PyObject *op, void *closure)\n"
"{\n"
" CustomObject *self = (CustomObject *) op;\n"
" return Py_NewRef(self->last);\n"
"}\n"
"\n"
"static int\n"
"Custom_setlast(PyObject *op, PyObject *value, void *closure)\n"
"{\n"
" CustomObject *self = (CustomObject *) op;\n"
" if (value == NULL) {\n"
" PyErr_SetString(PyExc_TypeError, \"Cannot delete the last "
"attribute\");\n"
" return -1;\n"
" }\n"
" if (!PyUnicode_Check(value)) {\n"
" PyErr_SetString(PyExc_TypeError,\n"
" \"The last attribute value must be a string\");\n"
" return -1;\n"
" }\n"
" Py_XSETREF(self->last, Py_NewRef(value));\n"
" return 0;\n"
"}\n"
"\n"
"static PyGetSetDef Custom_getsetters[] = {\n"
" {\"first\", Custom_getfirst, Custom_setfirst,\n"
" \"first name\", NULL},\n"
" {\"last\", Custom_getlast, Custom_setlast,\n"
" \"last name\", NULL},\n"
" {NULL} /* Sentinel */\n"
"};\n"
"\n"
"static PyObject *\n"
"Custom_name(PyObject *op, PyObject *Py_UNUSED(dummy))\n"
"{\n"
" CustomObject *self = (CustomObject *) op;\n"
" return PyUnicode_FromFormat(\"%S %S\", self->first, self->last);\n"
"}\n"
"\n"
"static PyMethodDef Custom_methods[] = {\n"
" {\"name\", Custom_name, METH_NOARGS,\n"
" \"Return the name, combining the first and last name\"\n"
" },\n"
" {NULL} /* Sentinel */\n"
"};\n"
"\n"
"static PyTypeObject CustomType = {\n"
" .ob_base = PyVarObject_HEAD_INIT(NULL, 0)\n"
" .tp_name = \"custom4.Custom\",\n"
" .tp_doc = PyDoc_STR(\"Custom objects\"),\n"
" .tp_basicsize = sizeof(CustomObject),\n"
" .tp_itemsize = 0,\n"
" .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | "
"Py_TPFLAGS_HAVE_GC,\n"
" .tp_new = Custom_new,\n"
" .tp_init = Custom_init,\n"
" .tp_dealloc = Custom_dealloc,\n"
" .tp_traverse = Custom_traverse,\n"
" .tp_clear = Custom_clear,\n"
" .tp_members = Custom_members,\n"
" .tp_methods = Custom_methods,\n"
" .tp_getset = Custom_getsetters,\n"
"};\n"
"\n"
"static int\n"
"custom_module_exec(PyObject *m)\n"
"{\n"
" if (PyType_Ready(&CustomType) < 0) {\n"
" return -1;\n"
" }\n"
"\n"
" if (PyModule_AddObjectRef(m, \"Custom\", (PyObject *) &CustomType) < 0) "
"{\n"
" return -1;\n"
" }\n"
"\n"
" return 0;\n"
"}\n"
"\n"
"static PyModuleDef_Slot custom_module_slots[] = {\n"
" {Py_mod_exec, custom_module_exec},\n"
" {Py_mod_multiple_interpreters, "
"Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED},\n"
" {0, NULL}\n"
"};\n"
"\n"
"static PyModuleDef custom_module = {\n"
" .m_base = PyModuleDef_HEAD_INIT,\n"
" .m_name = \"custom4\",\n"
" .m_doc = \"Example module that creates an extension type.\",\n"
" .m_size = 0,\n"
" .m_slots = custom_module_slots,\n"
"};\n"
"\n"
"PyMODINIT_FUNC\n"
"PyInit_custom4(void)\n"
"{\n"
" return PyModuleDef_Init(&custom_module);\n"
"}\n"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:716
msgid ""
"First, the traversal method lets the cyclic GC know about subobjects that "
"could participate in cycles::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:719
msgid ""
"static int\n"
"Custom_traverse(PyObject *op, visitproc visit, void *arg)\n"
"{\n"
" CustomObject *self = (CustomObject *) op;\n"
" int vret;\n"
" if (self->first) {\n"
" vret = visit(self->first, arg);\n"
" if (vret != 0)\n"
" return vret;\n"
" }\n"
" if (self->last) {\n"
" vret = visit(self->last, arg);\n"
" if (vret != 0)\n"
" return vret;\n"
" }\n"
" return 0;\n"
"}"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:737
msgid ""
"For each subobject that can participate in cycles, we need to call the :c:"
"func:`!visit` function, which is passed to the traversal method. The :c:func:"
"`!visit` function takes as arguments the subobject and the extra argument "
"*arg* passed to the traversal method. It returns an integer value that must "
"be returned if it is non-zero."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:743
msgid ""
"Python provides a :c:func:`Py_VISIT` macro that automates calling visit "
"functions. With :c:func:`Py_VISIT`, we can minimize the amount of "
"boilerplate in ``Custom_traverse``::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:747
msgid ""
"static int\n"
"Custom_traverse(PyObject *op, visitproc visit, void *arg)\n"
"{\n"
" CustomObject *self = (CustomObject *) op;\n"
" Py_VISIT(self->first);\n"
" Py_VISIT(self->last);\n"
" return 0;\n"
"}"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:757
msgid ""
"The :c:member:`~PyTypeObject.tp_traverse` implementation must name its "
"arguments exactly *visit* and *arg* in order to use :c:func:`Py_VISIT`."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:760
msgid ""
"Second, we need to provide a method for clearing any subobjects that can "
"participate in cycles::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:763
msgid ""
"static int\n"
"Custom_clear(PyObject *op)\n"
"{\n"
" CustomObject *self = (CustomObject *) op;\n"
" Py_CLEAR(self->first);\n"
" Py_CLEAR(self->last);\n"
" return 0;\n"
"}"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:772
msgid ""
"Notice the use of the :c:func:`Py_CLEAR` macro. It is the recommended and "
"safe way to clear data attributes of arbitrary types while decrementing "
"their reference counts. If you were to call :c:func:`Py_XDECREF` instead on "
"the attribute before setting it to ``NULL``, there is a possibility that the "
"attribute's destructor would call back into code that reads the attribute "
"again (*especially* if there is a reference cycle)."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:780
msgid "You could emulate :c:func:`Py_CLEAR` by writing::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:782
msgid ""
"PyObject *tmp;\n"
"tmp = self->first;\n"
"self->first = NULL;\n"
"Py_XDECREF(tmp);"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:787
msgid ""
"Nevertheless, it is much easier and less error-prone to always use :c:func:"
"`Py_CLEAR` when deleting an attribute. Don't try to micro-optimize at the "
"expense of robustness!"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:791
msgid ""
"The deallocator ``Custom_dealloc`` may call arbitrary code when clearing "
"attributes. It means the circular GC can be triggered inside the function. "
"Since the GC assumes reference count is not zero, we need to untrack the "
"object from the GC by calling :c:func:`PyObject_GC_UnTrack` before clearing "
"members. Here is our reimplemented deallocator using :c:func:"
"`PyObject_GC_UnTrack` and ``Custom_clear``::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:798
msgid ""
"static void\n"
"Custom_dealloc(PyObject *op)\n"
"{\n"
" PyObject_GC_UnTrack(op);\n"
" (void)Custom_clear(op);\n"
" Py_TYPE(op)->tp_free(op);\n"
"}"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:806
msgid ""
"Finally, we add the :c:macro:`Py_TPFLAGS_HAVE_GC` flag to the class flags::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:808
msgid ""
".tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:810
msgid ""
"That's pretty much it. If we had written custom :c:member:`~PyTypeObject."
"tp_alloc` or :c:member:`~PyTypeObject.tp_free` handlers, we'd need to modify "
"them for cyclic garbage collection. Most extensions will use the versions "
"automatically provided."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:816
msgid "Subclassing other types"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:818
msgid ""
"It is possible to create new extension types that are derived from existing "
"types. It is easiest to inherit from the built in types, since an extension "
"can easily use the :c:type:`PyTypeObject` it needs. It can be difficult to "
"share these :c:type:`PyTypeObject` structures between extension modules."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:823
msgid ""
"In this example we will create a :class:`!SubList` type that inherits from "
"the built-in :class:`list` type. The new type will be completely compatible "
"with regular lists, but will have an additional :meth:`!increment` method "
"that increases an internal counter:"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:828
msgid ""
">>> import sublist\n"
">>> s = sublist.SubList(range(3))\n"
">>> s.extend(s)\n"
">>> print(len(s))\n"
"6\n"
">>> print(s.increment())\n"
"1\n"
">>> print(s.increment())\n"
"2"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:840
msgid ""
"#define PY_SSIZE_T_CLEAN\n"
"#include \n"
"\n"
"typedef struct {\n"
" PyListObject list;\n"
" int state;\n"
"} SubListObject;\n"
"\n"
"static PyObject *\n"
"SubList_increment(PyObject *op, PyObject *Py_UNUSED(dummy))\n"
"{\n"
" SubListObject *self = (SubListObject *) op;\n"
" self->state++;\n"
" return PyLong_FromLong(self->state);\n"
"}\n"
"\n"
"static PyMethodDef SubList_methods[] = {\n"
" {\"increment\", SubList_increment, METH_NOARGS,\n"
" PyDoc_STR(\"increment state counter\")},\n"
" {NULL},\n"
"};\n"
"\n"
"static int\n"
"SubList_init(PyObject *op, PyObject *args, PyObject *kwds)\n"
"{\n"
" SubListObject *self = (SubListObject *) op;\n"
" if (PyList_Type.tp_init(op, args, kwds) < 0)\n"
" return -1;\n"
" self->state = 0;\n"
" return 0;\n"
"}\n"
"\n"
"static PyTypeObject SubListType = {\n"
" .ob_base = PyVarObject_HEAD_INIT(NULL, 0)\n"
" .tp_name = \"sublist.SubList\",\n"
" .tp_doc = PyDoc_STR(\"SubList objects\"),\n"
" .tp_basicsize = sizeof(SubListObject),\n"
" .tp_itemsize = 0,\n"
" .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,\n"
" .tp_init = SubList_init,\n"
" .tp_methods = SubList_methods,\n"
"};\n"
"\n"
"static int\n"
"sublist_module_exec(PyObject *m)\n"
"{\n"
" SubListType.tp_base = &PyList_Type;\n"
" if (PyType_Ready(&SubListType) < 0) {\n"
" return -1;\n"
" }\n"
"\n"
" if (PyModule_AddObjectRef(m, \"SubList\", (PyObject *) &SubListType) < "
"0) {\n"
" return -1;\n"
" }\n"
"\n"
" return 0;\n"
"}\n"
"\n"
"static PyModuleDef_Slot sublist_module_slots[] = {\n"
" {Py_mod_exec, sublist_module_exec},\n"
" {Py_mod_multiple_interpreters, "
"Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED},\n"
" {0, NULL}\n"
"};\n"
"\n"
"static PyModuleDef sublist_module = {\n"
" .m_base = PyModuleDef_HEAD_INIT,\n"
" .m_name = \"sublist\",\n"
" .m_doc = \"Example module that creates an extension type.\",\n"
" .m_size = 0,\n"
" .m_slots = sublist_module_slots,\n"
"};\n"
"\n"
"PyMODINIT_FUNC\n"
"PyInit_sublist(void)\n"
"{\n"
" return PyModuleDef_Init(&sublist_module);\n"
"}\n"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:843
msgid ""
"As you can see, the source code closely resembles the :class:`!Custom` "
"examples in previous sections. We will break down the main differences "
"between them. ::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:846
msgid ""
"typedef struct {\n"
" PyListObject list;\n"
" int state;\n"
"} SubListObject;"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:851
msgid ""
"The primary difference for derived type objects is that the base type's "
"object structure must be the first value. The base type will already "
"include the :c:func:`PyObject_HEAD` at the beginning of its structure."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:855
msgid ""
"When a Python object is a :class:`!SubList` instance, its ``PyObject *`` "
"pointer can be safely cast to both ``PyListObject *`` and ``SubListObject "
"*``::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:858
msgid ""
"static int\n"
"SubList_init(PyObject *op, PyObject *args, PyObject *kwds)\n"
"{\n"
" SubListObject *self = (SubListObject *) op;\n"
" if (PyList_Type.tp_init(op, args, kwds) < 0)\n"
" return -1;\n"
" self->state = 0;\n"
" return 0;\n"
"}"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:868
msgid ""
"We see above how to call through to the :meth:`~object.__init__` method of "
"the base type."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:871
msgid ""
"This pattern is important when writing a type with custom :c:member:"
"`~PyTypeObject.tp_new` and :c:member:`~PyTypeObject.tp_dealloc` members. "
"The :c:member:`~PyTypeObject.tp_new` handler should not actually create the "
"memory for the object with its :c:member:`~PyTypeObject.tp_alloc`, but let "
"the base class handle it by calling its own :c:member:`~PyTypeObject.tp_new`."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:877
msgid ""
"The :c:type:`PyTypeObject` struct supports a :c:member:`~PyTypeObject."
"tp_base` specifying the type's concrete base class. Due to cross-platform "
"compiler issues, you can't fill that field directly with a reference to :c:"
"type:`PyList_Type`; it should be done in the :c:data:`Py_mod_exec` function::"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:883
msgid ""
"static int\n"
"sublist_module_exec(PyObject *m)\n"
"{\n"
" SubListType.tp_base = &PyList_Type;\n"
" if (PyType_Ready(&SubListType) < 0) {\n"
" return -1;\n"
" }\n"
"\n"
" if (PyModule_AddObjectRef(m, \"SubList\", (PyObject *) &SubListType) < "
"0) {\n"
" return -1;\n"
" }\n"
"\n"
" return 0;\n"
"}"
msgstr ""
#: ../../extending/newtypes_tutorial.rst:898
msgid ""
"Before calling :c:func:`PyType_Ready`, the type structure must have the :c:"
"member:`~PyTypeObject.tp_base` slot filled in. When we are deriving an "
"existing type, it is not necessary to fill out the :c:member:`~PyTypeObject."
"tp_alloc` slot with :c:func:`PyType_GenericNew` -- the allocation function "
"from the base type will be inherited."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:904
msgid ""
"After that, calling :c:func:`PyType_Ready` and adding the type object to the "
"module is the same as with the basic :class:`!Custom` examples."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:909
msgid "Footnotes"
msgstr "Funoten"
#: ../../extending/newtypes_tutorial.rst:910
msgid ""
"This is true when we know that the object is a basic type, like a string or "
"a float."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:913
msgid ""
"We relied on this in the :c:member:`~PyTypeObject.tp_dealloc` handler in "
"this example, because our type doesn't support garbage collection."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:916
msgid ""
"We now know that the first and last members are strings, so perhaps we could "
"be less careful about decrementing their reference counts, however, we "
"accept instances of string subclasses. Even though deallocating normal "
"strings won't call back into our objects, we can't guarantee that "
"deallocating an instance of a string subclass won't call back into our "
"objects."
msgstr ""
#: ../../extending/newtypes_tutorial.rst:922
msgid ""
"Also, even with our attributes restricted to strings instances, the user "
"could pass arbitrary :class:`str` subclasses and therefore still create "
"reference cycles."
msgstr ""