@@ -65,17 +65,14 @@ and the depth attribute readable but not writable.
...
@@ -65,17 +65,14 @@ and the depth attribute readable but not writable.
.. note::
.. note::
You can only expose simple C types, such as ints, floats and
You can only expose simple C types, such as ints, floats, and
strings, for Python access. You can also expose Python-valued attributes,
strings, for Python access. You can also expose Python-valued attributes.
although read-write exposure is only possible for generic Python attributes
(of type object). If the attribute is declared to be of an extension type, it
must be exposed :keyword:`readonly`.
.. note::
.. note::
Also the :keyword:`public` and :keyword:`readonly` options apply only to
Also the :keyword:`public` and :keyword:`readonly` options apply only to
Python access, not direct access. All the attributes of an extension type
Python access, not direct access. All the attributes of an extension type
are always readable and writable by direct access.
are always readable and writable by C-level access.
Type declarations
Type declarations
===================
===================
...
@@ -114,6 +111,45 @@ The same consideration applies to local variables, for example,::
...
@@ -114,6 +111,45 @@ The same consideration applies to local variables, for example,::
sh2.height = sh1.height
sh2.height = sh1.height
return sh2
return sh2
Type Testing and Casting
------------------------
Suppose I have a method :meth:`quest` which returns an object of type :class:`Shrubbery`.
To access it's width I could write::
cdef Shrubbery sh = quest()
print sh.width
which requires the use of a local variable and performs a type test on assignment.
If you *know* the return value of :meth:`quest` will be of type :class:`Shrubbery`
you can use a cast to write::
print (<Shrubbery>quest()).width
This may be dangerous if :meth:`quest()` is not actually a :class:`Shrubbery`, as it
will try to access width as a C struct member which may not exist. At the C level,
rather than raising an :class:`AttributeError`, either an nonsensical result will be
returned (interpreting whatever data is at at that address as an int) or a segfault
may result from trying to access invalid memory. Instead, one can write::
print (<Shrubbery?>quest()).width
which performs a type check (possibly raising a :class:`TypeError`) before making the
cast and allowing the code to proceed.
To explicitly test the type of an object, use the :meth:`isinstance` method. By default,
in Python, the :meth:`isinstance` method checks the :class:`__class__` attribute of the
first argument to determine if it is of the required type. However, this is potentially
unsafe as the :class:`__class__` attribute can be spoofed or changed, but the C structure
of an extension type must be correct to access its :keyword:`cdef` attributes and call its :keyword:`cdef` methods. Cython detects if the second argument is a known extension
type and does a type check instead, analogous to Pyrex's :meth:`typecheck`.
The old behavior is always available by passing a tuple as the second parameter::
print isinstance(sh, Shrubbery) # Check the type of sh