From 2167593272aa9f8574015c23855824c6e1ba835e Mon Sep 17 00:00:00 2001 From: "ggellner@encolpuis" Date: Sat, 27 Sep 2008 16:46:32 -0400 Subject: [PATCH] Refactored some source includes. Changed the overview to be shorter and give credit to pyrex more prominantly. Added documentation to automatic range() conversion --- docs/language_basics.rst | 31 ++++++++++---- docs/overview.rst | 66 +++++++---------------------- docs/pyrex_differences.rst | 22 ++-------- docs/tutorial.rst | 60 ++++++-------------------- examples/tutorial/fib1/fib.pyx | 6 +++ examples/tutorial/fib1/setup.py | 9 ++++ examples/tutorial/primes/primes.py | 15 +++++++ examples/tutorial/primes/primes.pyx | 19 +++++++++ examples/tutorial/primes/setup.py | 9 ++++ 9 files changed, 113 insertions(+), 124 deletions(-) create mode 100644 examples/tutorial/fib1/fib.pyx create mode 100644 examples/tutorial/fib1/setup.py create mode 100644 examples/tutorial/primes/primes.py create mode 100644 examples/tutorial/primes/primes.pyx create mode 100644 examples/tutorial/primes/setup.py diff --git a/docs/language_basics.rst b/docs/language_basics.rst index 0bbf50ea..85ee148b 100644 --- a/docs/language_basics.rst +++ b/docs/language_basics.rst @@ -292,23 +292,36 @@ Keep in mind that there are some differences in operator precedence between Python and C, and that Cython uses the Python precedences, not the C ones. Integer for-loops ------------------ +------------------ You should be aware that a for-loop such as:: for i in range(n): ... -won't be very fast, even if i and n are declared as C integers, because range -is a Python function. For iterating over ranges of integers, Cython has another -form of for-loop:: +won't be very fast if ``i`` is not a :keyword:`cdef` integer type. +For iterating over ranges of integers, Cython has another form of for-loop:: for i from 0 <= i < n: ... +or:: + + for i from 0 <= i < n by s: + ... + +where ``s`` is some integer step size. + If the loop variable and the lower and upper bounds are all C integers, this form of loop will be much faster, because Cython will translate it into pure C -code. +code. + +.. note:: + This is not necessary if ``i`` is a C integer type and ``n`` can be + determined at compile time. Just use the idiomatic :func:`range` loop, if + you are worried that the loop is not being converted correctly use the + annotate feature of the cython commandline (``-a``) to easily see the + generated C code. See :ref:`automatic-range-conversion` Some things to note about the for-from loop: @@ -322,9 +335,6 @@ Some things to note about the for-from loop: Like other Python looping statements, break and continue may be used in the body, and the loop may have an else clause. -.. note:: - - See :ref:`automatic-range-conversion` Error return values ------------------- @@ -409,7 +419,10 @@ return value and raise it yourself, for example,:: raise SpamError("Couldn't open the spam file") The include statement ---------------------- +---------------------- + +.. warning:: + This feature is deprecated. Use :ref:`sharing-declarations-label` instead. A Cython source file can include material from other files using the include statement, for example:: diff --git a/docs/overview.rst b/docs/overview.rst index 53248af8..0dc43801 100644 --- a/docs/overview.rst +++ b/docs/overview.rst @@ -6,61 +6,27 @@ Overview ******** -A language for writing Python extension modules +About Cython +============== -What is Cython all about? -========================= +Cython is a language that makes writing C extensions for the Python language +as easy as Python itself. Cython is based on the well-known `Pyrex +`_ language by Greg Ewing, +but supports more cutting edge functionality and optimizations [#]_. +The Cython language is very close to the Python language, but Cython +additionally supports calling C functions and declaring C types on variables +and class attributes. This allows the compiler to generate very efficient C +code from Cython code. -Cython is a language specially designed for writing Python extension modules. -It's designed to bridge the gap between the nice, high-level, easy-to-use -world of Python and the messy, low-level world of C. - -You may be wondering why anyone would want a special language for this. Python -is really easy to extend using C or C++, isn't it? Why not just write your -extension modules in one of those languages? - -Well, if you've ever written an extension module for Python, you'll know that -things are not as easy as all that. First of all, there is a fair bit of -boilerplate code to write before you can even get off the ground. Then you're -faced with the problem of converting between Python and C data types. For the -basic types such as numbers and strings this is not too bad, but anything more -elaborate and you're into picking Python objects apart using the Python/C API -calls, which requires you to be meticulous about maintaining reference counts, -checking for errors at every step and cleaning up properly if anything goes -wrong. Any mistakes and you have a nasty crash that's very difficult to debug. - -Various tools have been developed to ease some of the burdens of producing -extension code, of which perhaps SWIG is the best known. SWIG takes a -definition file consisting of a mixture of C code and specialised -declarations, and produces an extension module. It writes all the boilerplate -for you, and in many cases you can use it without knowing about the Python/C -API. But you need to use API calls if any substantial restructuring of the -data is required between Python and C. - -What's more, SWIG gives you no help at all if you want to create a new -built-in Python type. It will generate pure-Python classes which wrap (in a -slightly unsafe manner) pointers to C data structures, but creation of true -extension types is outside its scope. - -Another notable attempt at making it easier to extend Python is PyInline , -inspired by a similar facility for Perl. PyInline lets you embed pieces of C -code in the midst of a Python file, and automatically extracts them and -compiles them into an extension. But it only converts the basic types -automatically, and as with SWIG, it doesn't address the creation of new -Python types. - -Cython aims to go far beyond what any of these previous tools provides. Cython -deals with the basic types just as easily as SWIG, but it also lets you write -code to convert between arbitrary Python data structures and arbitrary C data -structures, in a simple and natural way, without knowing anything about the -Python/C API. That's right -- nothing at all! Nor do you have to worry about -reference counting or error checking -- it's all taken care of automatically, -behind the scenes, just as it is in interpreted Python code. And what's more, -Cython lets you define new built-in Python types just as easily as you can -define new classes in Python. +This makes Cython the ideal language for wrapping external C libraries, +and for fast C modules that speed up the execution of Python code. Future Plans ============ Cython is not finished. Substantial tasks remaining. See :ref:`cython-limitations-label` for a current list. +.. rubric:: Footnotes + +.. [#] For differences with Pyrex see :ref:`pyrex-differences-label`. + diff --git a/docs/pyrex_differences.rst b/docs/pyrex_differences.rst index 3009699f..fd471058 100644 --- a/docs/pyrex_differences.rst +++ b/docs/pyrex_differences.rst @@ -1,5 +1,7 @@ .. highlight:: cython +.. _pyrex-differences-label: + Differences between Cython and Pyrex ==================================== @@ -17,20 +19,6 @@ a list. Also, use the :keyword:`for` ... :keyword:`from` syntax too, e.g.:: [i*i for i from 0 <= i < 10] -In-place operators ------------------- - -The following is now legal:: - - x += 10 - -for all single-character operators, for both python and :keyword:`cdef` variables. Side -effects behave properly, i.e. for:: - - L[foo()] += bar() - -:func:`foo` is called exactly once, before :func:`bar`. - Conditional expressions "x if b else y" (python 2.5) ---------------------------------------------------- @@ -168,13 +156,9 @@ See :ref:`early-binding-speed-label` for explanation and usage tips. .. _automatic-range-conversion: -(Optional) automatic range conversion +Automatic range conversion ------------------------------------- -:: - - $cython --convert-range - This will convert statements of the form ``for i in range(...)`` to ``for i from ...`` when ``i`` is any cdef'd integer type, and the direction (i.e. sign of step) can be determined. diff --git a/docs/tutorial.rst b/docs/tutorial.rst index 42cc9b37..3800a203 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -30,17 +30,15 @@ available to you -- even in the midst of manipulating C data. Cython Hello World =================== -As Cython can accept almost any valid plain python file (though see the -`exceptions`), one of the hardest things in getting started is just figuring -out how to compile your file. +As Cython can accept almost any valid python source file, one of the hardest +things in getting started is just figuring out how to compile your extension. So lets start with the canonical python hello world:: print "Hello World" So the first thing to do is rename the file to :file:`helloworld.pyx`. Now we -need to make the :file:`setup.py`, which is like a python Makefile if you are -familiar.:: +need to make the :file:`setup.py`, which is like a python Makefile.:: from distutils.core import setup from distutils.extension import Extension @@ -55,42 +53,31 @@ To use this to build your Cython file use the commandline options:: $ python setup.py build_ext --inplace -Which will leave a file in your local directory called `helloworld.so`. Now to -use this file start the python interpreter and:: +Which will leave a file in your local directory called `helloworld.so` in unix +or `helloworld.dll` in Windows. Now to use this file start the python +interpreter and simply import it as if it was a regular python module:: >>> import helloworld "Hello World" -Congratulations! You know know how to build a Cython extension. But So Far -this example doesn't really show us why we would even want to use Cython, so -lets do a more realistic example. +Congratulations! You now know how to build a Cython extension. But So Far +this example doesn't really give a feeling why one would ever want to use Cython, so +lets create a more realistic example. Fibonacci Fun ============== -From the official Python tutorial a simple fibonacci function is defined as:: +From the official Python tutorial a simple fibonacci function is defined as: - def fib(n): - """Print the Fibonacci series up to n.""" - a, b = 0, 1 - while b < n: - print b, - a, b = b, a + b +.. literalinclude:: ../examples/tutorial/fib1/fib.pyx Now following the steps for the Hello World example we first rename the file to have a `.pyx` extension, lets say :file:`fib.pyx`, then we create the :file:`setup.py` file. Using the file created for the Hello World example, all that you need to change is the name of the Cython filename, and the resulting -module name, doing this we have:: +module name, doing this we have: - from distutils.core import setup - from distutils.extension import Extension - from Cython.Distutils import build_ext - - setup( - cmdclass = {'build_ext': build_ext}, - ext_modules = [Extension("fib", ["fib.pyx"])] - ) +.. literalinclude:: ../examples/tutorial/fib1/setup.py Build the extension with the same command used for the helloworld.pyx:: @@ -111,28 +98,9 @@ them as a Python list. :file:`primes.pyx`: -.. sourcecode:: cython +.. literalinclude:: ../examples/tutorial/primes/primes.pyx :linenos: - def primes(int kmax): - cdef int n, k, i - cdef int p[1000] - result = [] - if kmax > 1000: - kmax = 1000 - k = 0 - n = 2 - while k < kmax: - i = 0 - while i < k and n % p[i] != 0: - i = i + 1 - if i == k: - p[k] = n - k = k + 1 - result.append(n) - n = n + 1 - return result - You'll see that it starts out just like a normal Python function definition, except that the parameter ``kmax`` is declared to be of type ``int`` . This means that the object passed will be converted to a C integer (or a diff --git a/examples/tutorial/fib1/fib.pyx b/examples/tutorial/fib1/fib.pyx new file mode 100644 index 00000000..043d71e5 --- /dev/null +++ b/examples/tutorial/fib1/fib.pyx @@ -0,0 +1,6 @@ +def fib(n): + """Print the Fibonacci series up to n.""" + a, b = 0, 1 + while b < n: + print b, + a, b = b, a + b diff --git a/examples/tutorial/fib1/setup.py b/examples/tutorial/fib1/setup.py new file mode 100644 index 00000000..bda9101b --- /dev/null +++ b/examples/tutorial/fib1/setup.py @@ -0,0 +1,9 @@ +from distutils.core import setup +from distutils.extension import Extension +from Cython.Distutils import build_ext + +setup( + cmdclass = {'build_ext': build_ext}, + ext_modules = [Extension("fib", ["fib.pyx"])] +) + diff --git a/examples/tutorial/primes/primes.py b/examples/tutorial/primes/primes.py new file mode 100644 index 00000000..a25fdd80 --- /dev/null +++ b/examples/tutorial/primes/primes.py @@ -0,0 +1,15 @@ +def primes(kmax): + result = [] + if kmax > 1000: + kmax = 1000 + while k < kmax: + i = 0 + while i < k and n % p[i] != 0: + i = i + 1 + if i == k: + p[k] = n + k = k + 1 + result.append(n) + n = n + 1 + return result + diff --git a/examples/tutorial/primes/primes.pyx b/examples/tutorial/primes/primes.pyx new file mode 100644 index 00000000..63c42a5c --- /dev/null +++ b/examples/tutorial/primes/primes.pyx @@ -0,0 +1,19 @@ +def primes(int kmax): + cdef int n, k, i + cdef int p[1000] + result = [] + if kmax > 1000: + kmax = 1000 + k = 0 + n = 2 + while k < kmax: + i = 0 + while i < k and n % p[i] != 0: + i = i + 1 + if i == k: + p[k] = n + k = k + 1 + result.append(n) + n = n + 1 + return result + diff --git a/examples/tutorial/primes/setup.py b/examples/tutorial/primes/setup.py new file mode 100644 index 00000000..ca5ea49f --- /dev/null +++ b/examples/tutorial/primes/setup.py @@ -0,0 +1,9 @@ +from distutils.core import setup +from distutils.extension import Extension +from Cython.Distutils import build_ext + +setup( + cmdclass = {'build_ext': build_ext}, + ext_modules = [Extension("primes", ["primes.pyx"])] +) + -- 2.26.2