@@ -207,9 +207,11 @@ Building your extension
207207 description='simple c extension for an example',
208208 ext_modules=[Extension('add', sources=['add.c'])],
209209 )
210+
210211Run the setup.py::
211212
212213 python setup.py build_ext --inplace
214+
213215(you can also just do ``install `` or ``develop `` if you want to properly installed)
214216
215217Run the tests
@@ -319,3 +321,301 @@ Example::
319321Further reading:
320322
321323http://docs.python.org/2/library/ctypes.html
324+
325+
326+ Calling functions with ctypes
327+ ==============================
328+
329+ The shared lib must be loaded::
330+
331+ add = ctypes.cdll.LoadLibrary("add.so")
332+
333+ An already loaded lib can be loaded with:
334+
335+ libc = ctypes.CDLL("/usr/lib/libc.dylib")
336+
337+ ctypes comes with a utility to help find libs::
338+
339+ ctypes.util.find_library(name)
340+
341+ (good for system libs)
342+
343+ .. nextslide ::
344+
345+ Once loaded, a ctypes wrapper around a c function can be called directly::
346+
347+ print add.add(3,4)
348+
349+ But....
350+
351+
352+ C is statically typed -- once compiled, the function must be called with the correct types.
353+
354+ ctypes Data Types
355+ =================
356+
357+ ctypes will auto-translate these native types:
358+
359+ - ``None ``
360+ - int
361+ - byte strings (``bytes() ``, ``str() ``)
362+ - ``unicode `` (careful! unicode is ugly in C!)
363+
364+ These can be directly used as parameters when calling C functions.
365+
366+ .. nextslide ::
367+
368+ Most types must be wrapped in a ctypes data type::
369+
370+ printf("An int %d, a double %f\n", 1234, c_double(3.14))
371+
372+ There are ctypes wrappers for all the "standard" C types
373+
374+ http://docs.python.org/2/library/ctypes.html#fundamental-data-types
375+
376+
377+ You can also do pointers to types::
378+
379+ a_lib.a_function( ctypes.byref(c_float(x)))
380+
381+ http://docs.python.org/2/library/ctypes.html#passing-pointers-or-passing-parameters-by-reference
382+
383+ .. nextslide :: C structs
384+
385+ You can define C structs::
386+
387+ >>> class POINT(ctypes.Structure):
388+ ... _fields_ = [("x", ctypes.c_int),
389+ ... ("y", ctypes.c_int)]
390+ ...
391+ >>> point = POINT(10, 20)
392+ >>> print point.x, point.y
393+ 10 20
394+ >>> point = POINT(y=5)
395+ >>> print point.x, point.y
396+ 0 5
397+
398+ .. nextslide :: Custom Python Classes
399+
400+ You can define how to pass data from your custom classes to ctypes:
401+
402+ Define an ``_as_parameter_ `` attribute (or property)::
403+
404+ class MyObject(object):
405+ def __init__(self, number):
406+ self._as_parameter_ = number
407+
408+ obj = MyObject(32)
409+ printf("object value: %d\n", obj)
410+
411+ http://docs.python.org/2/library/ctypes.html#fundamental-data-types
412+
413+ (careful with types here!)
414+
415+ .. nextslide :: Return Types
416+
417+ To defining the return type, define the ``restype `` attribute.
418+
419+ Pre-defining the entire function signature::
420+
421+ libm.pow.restype = ctypes.c_double
422+ libm.pow.argtypes = [ctypes.c_double, ctypes.c_double]
423+
424+ And you can just call it like a regular python function -- ctypes will type check/convert at run time::
425+
426+ In [10]: libm.pow('a string', 4)
427+ ---------------------------------------------------------------------------
428+ ArgumentError Traceback (most recent call last)
429+ <ipython-input-10-01be690a307b> in <module>()
430+ ----> 1 libm.pow('a string', 4)
431+
432+ ArgumentError: argument 1: <type 'exceptions.TypeError'>: wrong type
433+
434+ Some more features
435+ ===================
436+
437+ Defining callbacks into Python code from C::
438+
439+ ctypes.CFUNCTYPE(restype, *argtypes, use_errno=False, use_last_error=False)
440+
441+ http://docs.python.org/2/library/ctypes.html#ctypes.CFUNCTYPE
442+
443+ Numpy provides utilities for numpy arrays:
444+
445+ http://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.ctypes.html
446+
447+ (works well for C code that takes "classic" C arrays)
448+
449+
450+ Summary:
451+ ========
452+
453+ * ``ctypes `` allows you to call shared libraries:
454+
455+ - Your own custom libs
456+ - System libs
457+ - Proprietary libs
458+
459+ * Supports almost all of C:
460+
461+ - Custom data types
462+
463+ - structs
464+ - unions
465+ - pointers
466+
467+ - callbacks
468+
469+ .. nextslide ::
470+
471+ * Upside:
472+
473+ - You can call system libs with little code
474+ - You don't need to compile anything
475+
476+ - at least for system and pre-compiled libs
477+
478+ * Downsides:
479+
480+ - You need to specify the interface
481+
482+ - and it is NOT checked for you!
483+
484+ - Translation is done on the fly at run time
485+
486+ - performance considerations
487+
488+ LAB
489+ ====
490+
491+ In ``code/ctypes `` you'll find ``add.c ``
492+
493+ You can build a shared lib with it with ``make ``
494+ (``make.bat ``) on Windows.
495+
496+ ``test_ctypes.py `` will call that dll, and a few system dlls.
497+
498+ * Take a look at what's there, and how it works.
499+ * add another function to add.c, that takes different types (maybe divide?)
500+ * rebuild, and figure out how to call it with ctypes.
501+
502+ * Try calling other system functions with ctypes.
503+
504+
505+ *******
506+ Cython
507+ *******
508+
509+ A Python like language with static types which compiles down to C code for Python extensions.
510+
511+ Cython
512+ =======
513+
514+ * Can write pure python
515+ - Fully understands the python types
516+
517+ * With careful typing -- you get pure C (and pure C speed)
518+
519+ * Can also call other C code: libraries or compiled in.
520+
521+ * Used for custom Python extensions and/or call C and C++ code.
522+
523+ .. nextslide ::
524+
525+ Further reading:
526+
527+ Web site:
528+
529+ http://www.cython.org/
530+
531+ Documentation:
532+
533+ http://docs.cython.org/
534+
535+ Wiki:
536+
537+ https://github.com/cython/cython/wiki
538+
539+
540+
541+ Developing with Cython
542+ ========================
543+
544+ First, install cython with::
545+
546+ ``pip install cython``
547+
548+ Cython files end in the .pyx extension. An example add.pyx::
549+
550+ def add(int x, int y):
551+ cdef int result=0
552+ result = x + y
553+ return result
554+
555+
556+ Basic Cython
557+ =============
558+
559+ Cython functions can be declared three ways::
560+
561+ def foo # callable from Python
562+
563+ cdef foo # only callable from Cython/C
564+
565+ cpdef foo # callable from both Cython and Python
566+
567+ Once your .pyx file is created, it is converted to C via
568+
569+
570+ cython cy_add.pyx
571+ Generate "annoted" C code in HTML
572+
573+
574+ cython -a cy_add.pyx
575+ To build your Python extension:
576+
577+
578+ python cy_setup.py build_ext --inplace # note Cython defines its' own build_ext in Cython.Distutils.build_ext
579+
580+ Cython can compile pure Python code to C to provide a performance improvement
581+
582+
583+
584+ ::
585+
586+
587+
588+
589+ Consider a more expensive function
590+
591+
592+ def f(x):
593+ return x**2-x
594+
595+ def integrate_f(a, b, N):
596+ s = 0
597+ dx = (b-a)/N
598+ for i in range(N):
599+ s += f(a+i*dx)
600+ return s * dx
601+
602+
603+ Impovements with static typing
604+
605+ Convert the dynamically typed variables to static types and measure performance improvement before and after
606+ Can static types and dynamic types be mixed?
607+ Check the performance in converting the function type to static (see here)
608+ Use cython -a to compare the generated C code in all cases
609+
610+ def f(x):
611+ return x**2-x
612+
613+ def integrate_f(a, b, N):
614+ s = 0
615+ dx = (b-a)/N
616+ for i in range(N):
617+ s += f(a+i*dx)
618+ return s * dx
619+
620+
621+
0 commit comments