summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author0dminnimda <52697657+0dminnimda@users.noreply.github.com>2021-07-14 22:02:02 +0300
committerGitHub <noreply@github.com>2021-07-14 21:02:02 +0200
commit54fa2b822565fc9ddef89aa399eb7562d5b76f07 (patch)
tree1aa89d6a85ea296dc85721358dd0be782c36c539
parent696a1959b44ca9028d3f9468723b6b24335ad921 (diff)
downloadcython-54fa2b822565fc9ddef89aa399eb7562d5b76f07.tar.gz
docs: Pythonise the "Extension types (aka. cdef classes)" page (cdef_classes.rst) (GH-4232)
-rw-r--r--docs/examples/tutorial/cdef_classes/integrate.py17
-rw-r--r--docs/examples/tutorial/cdef_classes/integrate.pyx3
-rw-r--r--docs/examples/tutorial/cdef_classes/math_function_2.py5
-rw-r--r--docs/examples/tutorial/cdef_classes/math_function_2.pyx2
-rw-r--r--docs/examples/tutorial/cdef_classes/nonecheck.py20
-rw-r--r--docs/examples/tutorial/cdef_classes/nonecheck.pyx1
-rw-r--r--docs/examples/tutorial/cdef_classes/sin_of_square.py13
-rw-r--r--docs/examples/tutorial/cdef_classes/sin_of_square.pyx4
-rw-r--r--docs/examples/tutorial/cdef_classes/wave_function.py22
-rw-r--r--docs/examples/tutorial/cdef_classes/wave_function.pyx1
-rw-r--r--docs/src/tutorial/cdef_classes.rst97
-rw-r--r--docs/src/two-syntax-variants-used22
12 files changed, 173 insertions, 34 deletions
diff --git a/docs/examples/tutorial/cdef_classes/integrate.py b/docs/examples/tutorial/cdef_classes/integrate.py
new file mode 100644
index 000000000..cd02554e5
--- /dev/null
+++ b/docs/examples/tutorial/cdef_classes/integrate.py
@@ -0,0 +1,17 @@
+from cython.cimports.sin_of_square import Function, SinOfSquareFunction
+
+def integrate(f: Function, a: float, b: float, N: cython.int):
+ i: cython.int
+
+ if f is None:
+ raise ValueError("f cannot be None")
+
+ s: float = 0
+ dx: float = (b - a) / N
+
+ for i in range(N):
+ s += f.evaluate(a + i * dx)
+
+ return s * dx
+
+print(integrate(SinOfSquareFunction(), 0, 1, 10000))
diff --git a/docs/examples/tutorial/cdef_classes/integrate.pyx b/docs/examples/tutorial/cdef_classes/integrate.pyx
index a3e96f398..ad4c8540b 100644
--- a/docs/examples/tutorial/cdef_classes/integrate.pyx
+++ b/docs/examples/tutorial/cdef_classes/integrate.pyx
@@ -5,10 +5,13 @@ def integrate(Function f, double a, double b, int N):
cdef double s, dx
if f is None:
raise ValueError("f cannot be None")
+
s = 0
dx = (b - a) / N
+
for i in range(N):
s += f.evaluate(a + i * dx)
+
return s * dx
print(integrate(SinOfSquareFunction(), 0, 1, 10000))
diff --git a/docs/examples/tutorial/cdef_classes/math_function_2.py b/docs/examples/tutorial/cdef_classes/math_function_2.py
new file mode 100644
index 000000000..ba5917639
--- /dev/null
+++ b/docs/examples/tutorial/cdef_classes/math_function_2.py
@@ -0,0 +1,5 @@
+@cython.cclass
+class Function:
+ @cython.ccall
+ def evaluate(self, x: float) -> float:
+ return 0
diff --git a/docs/examples/tutorial/cdef_classes/math_function_2.pyx b/docs/examples/tutorial/cdef_classes/math_function_2.pyx
index 7d1446b7c..a4bdb7aa2 100644
--- a/docs/examples/tutorial/cdef_classes/math_function_2.pyx
+++ b/docs/examples/tutorial/cdef_classes/math_function_2.pyx
@@ -1,3 +1,5 @@
+
cdef class Function:
+
cpdef double evaluate(self, double x) except *:
return 0
diff --git a/docs/examples/tutorial/cdef_classes/nonecheck.py b/docs/examples/tutorial/cdef_classes/nonecheck.py
new file mode 100644
index 000000000..dccb97435
--- /dev/null
+++ b/docs/examples/tutorial/cdef_classes/nonecheck.py
@@ -0,0 +1,20 @@
+# cython: nonecheck=True
+# ^^^ Turns on nonecheck globally
+
+import cython
+
+@cython.cclass
+class MyClass:
+ pass
+
+# Turn off nonecheck locally for the function
+@cython.nonecheck(False)
+def func():
+ obj: MyClass = None
+ try:
+ # Turn nonecheck on again for a block
+ with cython.nonecheck(True):
+ print(obj.myfunc()) # Raises exception
+ except AttributeError:
+ pass
+ print(obj.myfunc()) # Hope for a crash!
diff --git a/docs/examples/tutorial/cdef_classes/nonecheck.pyx b/docs/examples/tutorial/cdef_classes/nonecheck.pyx
index 51c61006d..92c8fa42b 100644
--- a/docs/examples/tutorial/cdef_classes/nonecheck.pyx
+++ b/docs/examples/tutorial/cdef_classes/nonecheck.pyx
@@ -3,6 +3,7 @@
import cython
+
cdef class MyClass:
pass
diff --git a/docs/examples/tutorial/cdef_classes/sin_of_square.py b/docs/examples/tutorial/cdef_classes/sin_of_square.py
new file mode 100644
index 000000000..1904ea934
--- /dev/null
+++ b/docs/examples/tutorial/cdef_classes/sin_of_square.py
@@ -0,0 +1,13 @@
+from cython.cimports.libc.math import sin
+
+@cython.cclass
+class Function:
+ @cython.ccall
+ def evaluate(self, x: float) -> float:
+ return 0
+
+@cython.cclass
+class SinOfSquareFunction(Function):
+ @cython.ccall
+ def evaluate(self, x: float) -> float:
+ return sin(x ** 2)
diff --git a/docs/examples/tutorial/cdef_classes/sin_of_square.pyx b/docs/examples/tutorial/cdef_classes/sin_of_square.pyx
index d39ff374d..67af294b5 100644
--- a/docs/examples/tutorial/cdef_classes/sin_of_square.pyx
+++ b/docs/examples/tutorial/cdef_classes/sin_of_square.pyx
@@ -1,9 +1,13 @@
from libc.math cimport sin
+
cdef class Function:
+
cpdef double evaluate(self, double x) except *:
return 0
+
cdef class SinOfSquareFunction(Function):
+
cpdef double evaluate(self, double x) except *:
return sin(x ** 2)
diff --git a/docs/examples/tutorial/cdef_classes/wave_function.py b/docs/examples/tutorial/cdef_classes/wave_function.py
new file mode 100644
index 000000000..7ff59a762
--- /dev/null
+++ b/docs/examples/tutorial/cdef_classes/wave_function.py
@@ -0,0 +1,22 @@
+from cython.cimports.sin_of_square import Function
+
+@cython.cclass
+class WaveFunction(Function):
+
+ # Not available in Python-space:
+ offset: float
+
+ # Available in Python-space:
+ freq = cython.declare(cython.double, visibility='public')
+
+ # Available in Python-space, but only for reading:
+ scale = cython.declare(cython.double, visibility='readonly')
+
+ # Available in Python-space:
+ @property
+ def period(self):
+ return 1.0 / self.freq
+
+ @period.setter
+ def period(self, value):
+ self.freq = 1.0 / value
diff --git a/docs/examples/tutorial/cdef_classes/wave_function.pyx b/docs/examples/tutorial/cdef_classes/wave_function.pyx
index 82ba1c7bc..34b144667 100644
--- a/docs/examples/tutorial/cdef_classes/wave_function.pyx
+++ b/docs/examples/tutorial/cdef_classes/wave_function.pyx
@@ -1,5 +1,6 @@
from sin_of_square cimport Function
+
cdef class WaveFunction(Function):
# Not available in Python-space:
diff --git a/docs/src/tutorial/cdef_classes.rst b/docs/src/tutorial/cdef_classes.rst
index a95b802a8..ec2566dbd 100644
--- a/docs/src/tutorial/cdef_classes.rst
+++ b/docs/src/tutorial/cdef_classes.rst
@@ -1,5 +1,9 @@
+***********************************
Extension types (aka. cdef classes)
-===================================
+***********************************
+
+.. include::
+ ../two-syntax-variants-used
To support object-oriented programming, Cython supports writing normal
Python classes exactly as in Python:
@@ -24,17 +28,33 @@ single inheritance. Normal Python classes, on the other hand, can
inherit from any number of Python classes and extension types, both in
Cython code and pure Python code.
+.. tabs::
+ .. group-tab:: Pure Python
+
+ .. literalinclude:: ../../examples/tutorial/cdef_classes/math_function_2.py
+
+ .. group-tab:: Cython
+
+ .. literalinclude:: ../../examples/tutorial/cdef_classes/math_function_2.pyx
+
So far our integration example has not been very useful as it only
integrates a single hard-coded function. In order to remedy this,
with hardly sacrificing speed, we will use a cdef class to represent a
function on floating point numbers:
-.. literalinclude:: ../../examples/tutorial/cdef_classes/math_function_2.pyx
-
The directive cpdef makes two versions of the method available; one
fast for use from Cython and one slower for use from Python. Then:
-.. literalinclude:: ../../examples/tutorial/cdef_classes/sin_of_square.pyx
+.. tabs::
+ .. group-tab:: Pure Python
+
+ .. literalinclude:: ../../examples/tutorial/cdef_classes/sin_of_square.py
+ :caption: sin_of_square.py
+
+ .. group-tab:: Cython
+
+ .. literalinclude:: ../../examples/tutorial/cdef_classes/sin_of_square.pyx
+ :caption: sin_of_square.pyx
This does slightly more than providing a python wrapper for a cdef
method: unlike a cdef method, a cpdef method is fully overridable by
@@ -43,13 +63,24 @@ little calling overhead compared to a cdef method.
To make the class definitions visible to other modules, and thus allow for
efficient C-level usage and inheritance outside of the module that
-implements them, we define them in a :file:`sin_of_square.pxd` file:
+implements them, we define them in a ``.pxd`` file with the same name
+as the module:
.. literalinclude:: ../../examples/tutorial/cdef_classes/sin_of_square.pxd
+ :caption: sin_of_square.pxd
Using this, we can now change our integration example:
-.. literalinclude:: ../../examples/tutorial/cdef_classes/integrate.pyx
+.. tabs::
+ .. group-tab:: Pure Python
+
+ .. literalinclude:: ../../examples/tutorial/cdef_classes/integrate.py
+ :caption: integrate.py
+
+ .. group-tab:: Cython
+
+ .. literalinclude:: ../../examples/tutorial/cdef_classes/integrate.pyx
+ :caption: integrate.pyx
This is almost as fast as the previous code, however it is much more flexible
as the function to integrate can be changed. We can even pass in a new
@@ -70,32 +101,50 @@ into a Cython module.
Some notes on our new implementation of ``evaluate``:
- - The fast method dispatch here only works because ``evaluate`` was
- declared in ``Function``. Had ``evaluate`` been introduced in
- ``SinOfSquareFunction``, the code would still work, but Cython
- would have used the slower Python method dispatch mechanism
- instead.
+- The fast method dispatch here only works because ``evaluate`` was
+ declared in ``Function``. Had ``evaluate`` been introduced in
+ ``SinOfSquareFunction``, the code would still work, but Cython
+ would have used the slower Python method dispatch mechanism
+ instead.
- - In the same way, had the argument ``f`` not been typed, but only
- been passed as a Python object, the slower Python dispatch would
- be used.
+- In the same way, had the argument ``f`` not been typed, but only
+ been passed as a Python object, the slower Python dispatch would
+ be used.
- - Since the argument is typed, we need to check whether it is
- ``None``. In Python, this would have resulted in an ``AttributeError``
- when the ``evaluate`` method was looked up, but Cython would instead
- try to access the (incompatible) internal structure of ``None`` as if
- it were a ``Function``, leading to a crash or data corruption.
+- Since the argument is typed, we need to check whether it is
+ ``None``. In Python, this would have resulted in an ``AttributeError``
+ when the ``evaluate`` method was looked up, but Cython would instead
+ try to access the (incompatible) internal structure of ``None`` as if
+ it were a ``Function``, leading to a crash or data corruption.
There is a *compiler directive* ``nonecheck`` which turns on checks
for this, at the cost of decreased speed. Here's how compiler directives
are used to dynamically switch on or off ``nonecheck``:
-.. literalinclude:: ../../examples/tutorial/cdef_classes/nonecheck.pyx
+.. tabs::
+ .. group-tab:: Pure Python
+
+ .. literalinclude:: ../../examples/tutorial/cdef_classes/nonecheck.py
+ :caption: nonecheck.py
+
+ .. group-tab:: Cython
+
+ .. literalinclude:: ../../examples/tutorial/cdef_classes/nonecheck.pyx
+ :caption: nonecheck.pyx
Attributes in cdef classes behave differently from attributes in regular classes:
- - All attributes must be pre-declared at compile-time
- - Attributes are by default only accessible from Cython (typed access)
- - Properties can be declared to expose dynamic attributes to Python-space
+- All attributes must be pre-declared at compile-time
+- Attributes are by default only accessible from Cython (typed access)
+- Properties can be declared to expose dynamic attributes to Python-space
+
+.. tabs::
+ .. group-tab:: Pure Python
+
+ .. literalinclude:: ../../examples/tutorial/cdef_classes/wave_function.py
+ :caption: wave_function.py
+
+ .. group-tab:: Cython
-.. literalinclude:: ../../examples/tutorial/cdef_classes/wave_function.pyx
+ .. literalinclude:: ../../examples/tutorial/cdef_classes/wave_function.pyx
+ :caption: wave_function.pyx
diff --git a/docs/src/two-syntax-variants-used b/docs/src/two-syntax-variants-used
index ef7b38903..4a9815345 100644
--- a/docs/src/two-syntax-variants-used
+++ b/docs/src/two-syntax-variants-used
@@ -1,13 +1,15 @@
-This page uses two different syntax variants: the Cython specific ``cdef`` syntax
-and static Cython type declarations in
-:ref:`pure Python code <pep484_type_annotations>`,
-following `PEP-484 <https://www.python.org/dev/peps/pep-0484/>`_ type hints
-and `PEP 526 <https://www.python.org/dev/peps/pep-0526/>`_ variable annotations.
-To make good use of the latter, including C data types, etc., you need
-the special ``cython`` module, which you can import with
+.. note::
-.. code-block:: python
+ This page uses two different syntax variants: the Cython specific ``cdef`` syntax
+ and static Cython type declarations in
+ :ref:`pure Python code <pep484_type_annotations>`,
+ following `PEP-484 <https://www.python.org/dev/peps/pep-0484/>`_ type hints
+ and `PEP 526 <https://www.python.org/dev/peps/pep-0526/>`_ variable annotations.
+ To make good use of the latter, including C data types, etc., you need
+ the special ``cython`` module, which you can import with
- import cython
+ .. code-block:: python
-in the Python module that you want to compile.
+ import cython
+
+ in the Python module that you want to compile.