@@ -65,17 +65,14 @@ and the depth attribute readable but not writable.
.. note::
You can only expose simple C types, such as ints, floats and
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`.
You can only expose simple C types, such as ints, floats, and
strings, for Python access. You can also expose Python-valued attributes.
.. note::
Also the :keyword:`public` and :keyword:`readonly` options apply only to
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
===================
...
...
@@ -114,6 +111,45 @@ The same consideration applies to local variables, for example,::
sh2.height = sh1.height
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