diff --git a/development-tools/clinic.rst b/development-tools/clinic.rst index fe1361e88c..bc1090ffea 100644 --- a/development-tools/clinic.rst +++ b/development-tools/clinic.rst @@ -2000,25 +2000,31 @@ The generated glue code looks like this: .. versionadded:: 3.13 -.. _clinic-howto-getter: +.. _clinic-howto-pygetsetdef: -How to generate a getter ------------------------- +How to declare ``PyGetSetDef`` ("getter/setter") functions +---------------------------------------------------------- -"Getters" are C functions that facilitate property-like access for a class. -See :c:type:`getter <PyGetSetDef>` for details. -You can use the ``@getter`` directive to generate an "impl" function for a -getter using Argument Clinic. +"Getters" and "setters" are C functions defined in a :c:type:`PyGetSetDef` struct +that facilitate :py:class:`property`-like access for a class. +You can use the ``@getter`` and ``@setter`` directives to generate +"impl" functions using Argument Clinic. -This example -- taken from :cpy-file:`Modules/_io/bufferedio.c` -- -shows the use of ``@getter`` in combination with +This example --- taken from :cpy-file:`Modules/_io/textio.c` --- +shows the use of ``@getter`` and ``@setter`` in combination with the :ref:`@critical_section <clinic-howto-critical-sections>` directive (which achieves thread safety without causing deadlocks between threads):: /*[clinic input] @critical_section @getter - _io._Buffered.closed + _io.TextIOWrapper._CHUNK_SIZE + [clinic start generated code]*/ + + /*[clinic input] + @critical_section + @setter + _io.TextIOWrapper._CHUNK_SIZE [clinic start generated code]*/ The generated glue code looks like this: @@ -2026,26 +2032,44 @@ The generated glue code looks like this: .. code-block:: c static PyObject * - _io__Buffered_closed_get(buffered *self, void *context) + _io_TextIOWrapper__CHUNK_SIZE_get(textio *self, void *Py_UNUSED(context)) { PyObject *return_value = NULL; Py_BEGIN_CRITICAL_SECTION(self); - return_value = _io__Buffered_closed_get_impl(self); + return_value = _io_TextIOWrapper__CHUNK_SIZE_get_impl(self); Py_END_CRITICAL_SECTION(); return return_value; } + static int + _io_TextIOWrapper__CHUNK_SIZE_set(textio *self, PyObject *value, void *Py_UNUSED(context)) + { + int return_value; + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _io_TextIOWrapper__CHUNK_SIZE_set_impl(self, value); + Py_END_CRITICAL_SECTION(); + return return_value; + } + +.. note:: + + Getters and setters must be declared as separate functions. + The *value* parameter for a "setter" is added implicitly by Argument Clinic. + And then the implementation will work the same as a Python method which is -decorated by :py:class:`property`. +decorated by :py:class:`property`: .. code-block:: pycon - >>> import _io - >>> a = _io._BufferedIOBase() - >>> a.closed - False + >>> import sys, _io + >>> a = _io.TextIOWrapper(sys.stdout) + >>> a._CHUNK_SIZE + 8192 + >>> a._CHUNK_SIZE = 30 + >>> a._CHUNK_SIZE + 30 .. versionadded:: 3.13