Nichts falsch machen

»Das Netz ist voll mit mal mehr, mal weniger ernst gemeinten Aufzählungen der konkreten Vor- und Nachteile einzelner Programmiersprachen. Es ist zwar verlockend, diesen Listen eine weitere hinzuzufügen und dabei unsubtil die eigenen Vorlieben und Abneigungen einfließen zu lassen. Aber die Details solcher konkreten Empfehlungen ändern sich alle paar Jahre, und Sie lernen nicht viel dazu, wenn wir Ihnen einfach raten, »Nehmen Sie einfach Python, damit machen Sie nichts falsch!« (Obwohl Sie damit sicher wirklich nichts falsch machen.)« – Kathrin Passig und Johannes Jander, Weniger schlecht programmieren.

What's new in Cython 0.26?

Cython 0.26 has finally been released and it comes with some big and several smaller new features, contributed by quite a number of non-core developers.

Probably the biggest addition, definitely codewise, is support for Pythran as a backend for NumPy array expressions, contributed by Adrien Guinet. Pythran understands many usage patterns for NumPy, including array expressions and some methods, and can directly be used from within Cython to compile NumPy using code by setting the directive np_pythran=True. Thus, if Pythran is available at compile time, users can avoid writing manual loops and instead often just use NumPy in the same way as they would from Python. Note that this does not currently work generically with Cython's memoryviews, so you need to declare the specific numpy.ndarray[] types in order to benefit from the translation. Also, this requires the C++ mode in Cython as Pythran generates C++ code.

The other major new feature in this release, and likely with an even wider impact, is pickling support for cdef classes (a.k.a. extension types). This is enabled by default for all classes with Python compatible attribute types, which explicitly excludes pointers and unions. Classes with struct type attributes are also excluded for practical reasons (such as a high code overhead), but can be enabled to support pickling with the class decorator @cython.auto_pickle(True). This was a long-standing feature for which users previously had to implement the pickle protocol themselves. Since Cython has all information about the extension type and its attributes, however, there was no technical reason why it can't also generate the support for pickling them, and it now does.

As always, there are several new optimisations including speed-ups for abs(complex), comparing strings and dispatching to specialised function implementations based on fused types arguments. Particularly interesting might be the faster GIL re-entry with the directive fast_gil=True. It tries to remember the current GIL lock state in the fast thread local storage and avoids costly calls into the thread and GIL handling APIs if possible, even when calling across multiple Cython modules.

A slightly controversial change now hides the C code lines from tracebacks by default. Cython exceptions used to show the failing line number of the generated C code in addition to the Cython module code line, now only the latter is shown, like in Python code. On the one hand, this removes clutter that is irrelevant for most users. On the other hand, it hides information that could help developers debug failures from bug reports. For debugging purposes, the re-inclusion of C code lines can now be enabled with a runtime setting as follows:

import cython_runtime
cython_runtime.cline_in_traceback=True

What's new in Cython 0.25?

Cython 0.25 has been released in October 2016, so here's a quick writeup of the most relevant new features in this release.

My personal favourites are the call optimisations. Victor Stinner has done a great job throughout the year to optimise and benchmark different parts of CPython, and one of the things he came up with was a faster way to process function calls internally. For this, he added a new calling convention, METH_FASTCALL, which avoids tuple creation by passing positional arguments as a C array. I've added support for this to Cython and also ported a part of the CPython implementation to speed up calls to Python functions and PyCFunction functions from Cython code.

Further optimisations speed up f-string formatting, cython.inline() and some Python long integer operations (now also in Py2.7 and not only Py3).

The next big feature, one that has been on our list essentially forever, was finally added in 0.25. If you declare a special attribute __dict__ on a cdef class (a.k.a. extension type), if will have an instance dict that allows setting arbitrary attributes on the objects. Otherwise, extension types are limited to the declared attributes and trying to access undeclared ones would result in an AttributeError.

The C++ integration has received several minor improvements, including support for calling subclass methods from C++ classes implemented in Cython code, iterating over std::string with Cython's for-loop, typedef members in class declarations, or the typeid operator.

And a final little goodie is redundant declarations for pi and e in libc.math, which makes from libc cimport math pretty much a drop-in replacement for Python's import math.

Einflussreiche Bücher bei Skoobe

Die Webseite Highly Reco präsentiert hunderte Empfehlungen von Büchern, die berühmten Persönlichkeiten aus Wirtschaft und Gesellschaft etwas bedeutet haben. Seien es Bill Gates, Jessica Livingston, Warren Buffet oder Jeff Bezos, sie alle haben aus Büchern gelernt und schreiben dort über ihre Einflüsse und Ideengeber.

Bei Skoobe finden sich viele dieser Bücher im Abo-Katalog, hier eine kleine Auswahl einflussreicher Bücher, für alle, die ihnen nacheifern möchten.

Python-Bücher bei Skoobe

Neben einer riesigen Auswahl an Belletristik hat das eBook-Abo Skoobe auch zahlreiche gute Sachbücher im Angebot. Hier ist eine kleine Auswahl empfehlenswerter Python-Bücher aus der langen Liste bei Skoobe:

Cython for async networking

EuroPython 2016 seems to have three major topics this year, two of which make heavy use of Cython. The first, and probably most wonderful topic is beginners. The conference started with a workshop day on Sunday that was split between Django Girls and (other) Python beginners. The effect on the conference is totally visible: lots of new people walking around, visibly more Python beginners, and a clearly better ratio of women to men.

The other two big topics are: async networking and machine learning. Machine learning fills several talks and tutorials, and is obviously backed by Cython implemented tools in many corners.

For async networking, however, it might seem more surprising that Cython has such a good stand. But there are good reasons for it: even mostly I/O bound applications can hugely benefit from processing speed at the different layers, as Anton and I showed in our talk on Monday (see below). The deeper you step down into the machinery, however, the more important that speed becomes. And Yury Selivanov is giving an excellent example for that with his reimplementation of the asyncio event loop in Cython, named uvloop. Here is a blog post announcing uvloop.

Since the final talk recordings are not online yet, I have to refer to the live stream dumps for now.

The talk by Anton Caceres and me (we're both working at Skoobe) on Fast Async Code with Cython and AsyncIO starts at hour/minute 2:20 in the video. We provide examples and give motivations for compiling async code to speed up the processing and cut down the overall response latency. I'm also giving a very quick "Cython in 10 Minutes" intro to the language about half way through the talk.

Yury's talk on High Performance Networking in Python starts at minute 10. He gives a couple of great testimonials for Cython along the way, describing how the async/await support in Cython and the ease of talking to C libraries has enabled him to write a tool that beats the performance of well known async libraries in Go and Javascript.

What's new in Cython 0.24

Cython 0.24 has been released after about half a year of development. Time for a writeup of the most interesting features and improvements that already anticipate some of the new language features scheduled for CPython 3.6, at the end of this year.

My personal feature favourite is PEP-498 f-strings, e.g.

>>> value = 4 * 20
>>> f'The value is {value}.'
'The value is 80.'
>>> f'Four times the value is {4*value}.'
'Four times the value is 320.'

I was initially opposed to making them a part of the Python language, but then got convinced by others that they do bring an actual improvement by making the .format() string formatting a) the One Way To Do It compared to the other, older ways, and b) actually avoidable by providing a simpler language syntax for it. Especially the indirection of mapping values to format string names is now gone. Compare:

>>> 'The value is {value}.'.format(value=value)
'The value is 80.'

Sadly, we cannot use them in Cython itself (and we do a lot of string formatting in Cython), since the Python code of the compiler still has to run on Python 2.6. But at least code written in Cython can now make use of them, even if the compiled modules need to run in Python 2.6. The only required underlying Python feature is the __format__() protocol, which is available in all Python versions that Cython supports. Now that there is a dedicated syntax for string formatting that the compiler can see and explore, work has started for optimising it further at compile time.

EDIT (2016-04-12): f-string formatting is currently about 2-4 times as fast in Cython as in CPython 3.6.

Another new feature (also from Python 3.6) is the underscore separator in number literals, as defined by PEP 515. Since Cython is used a lot for developing numeric, scientific and algorithmic code, it's certainly helpful to be able to write

n = 1_000_000
x = 3.14159_26535_89

rather than the much less readable "count my digits" forms

n = 1000000
x = 3.141592653589

IDEs like PyCharm and PyDev will still have to catch up with these PEPs, but that will come. It seems that the PyCharm developers have already started working on this.

Some people complained about the size of the C files that Cython generates, so there is now a compiler option to disable the injection of C comments that show the original source code line right before the C code that came out of it. Just start your source file with

# cython: emit_code_comments=False

or, rather, pass the option from your setup.py script. The size reduction can be quite large. There is, however, a drawback: this makes source level debugging more difficult and also prevents coverage reporting. But since these are developer features, omitting the code comments can still be a good choice for release builds.

Pure Python mode (i.e. the optimised compilation of .py files) has also seen some improvements. C-tuples are now supported, i.e. you can write code as in the following (contrieved) example, which provides efficient access to C values of a tuple:

import cython

@cython.locals(t=(cython.int,cython.double), i=cython.int)
def func(t):
    x = 1.0
    for i in range(t[0]):
        x *= t[1]

Type inference will also automatically turn Python tuples into C tuples in some cases, but that already happend in previous releases.

Cython enums were adapted to PEP 435 enums and thus use the standard Python Enum type if available.

And the @property decorator is finally supported for methods in cdef classes. This removes the need for the old special property name: syntax block that Cython inherited from Pyrex. This syntax is now officially deprecated.

Apart from these, there is the usual list of optimisations, bug fixes and general improvements that went into this release. I am happy to notice that the number of people contributing to the code base has been steadily growing over the last couple of years. Thanks to everyone who helps making Cython better with every release!

And for those interested in learning Cython from a pro, there are still places left for the extensive Cython training that I'll be giving in Leipzig (DE) next June, 16-17th. It's part of a larger series of courses throughout that week on High-Performance Computing with Python.

EuroPython 2016

The list of accepted talks for EuroPython was published with lots of great talks and topics. I got my tutorial on Cython with NumPy accepted, as well as my talk on Fast Async Code with Cython and AsyncIO that I'm giving together with a collegue from Skoobe. I guess both proposals colided too heavily with the current list of hype buzzwords to get rejected. ;-)

Thanks to everyone who voted for them! Hope to see you there!

And in case you're interested in learning Cython from a pro, there are still places left for the extensive Cython training that I'll be giving in Leipzig (DE) next June, 16-17th. It's part of a larger series of courses throughout that week on High-Performance Computing with Python.

What's new in Cython 0.23

It was really nice to hear Cython being mentioned in pretty much every second talk at this year's EuroSciPy in Cambridge, either directly or by promoting tools that were themselves written in Cython. It seems to have become a key cornerstone in Python's ecosystem.

For me, this has been an intense conference summer overall, so I only just noticed that I hadn't written up anything about the long list of changes in Cython 0.23 yet. Well, apart from the changelog :). So here it goes.

Cython 0.23 is a major feature release. It implements the new language features of the new Python 3.5, but with the usual backports to make them available in Python 2.6 and later. My personal feature favourites are PEP 492 (async/await) and inlined generator expressions, but also the new support for Cython code coverage analysis with the coverage.py tool, that I blogged about already. Note that some Py3.5 features, such as the PEP 465 matrix multiplication operator, were already released early this year in Cython 0.22.

One of the greatest changes in Python 3.5, from a Cython perspective, is the shift from generators and coroutines as builtin types to making them ABCs, i.e. abstract base classes in the collections.abc module. This enables full interoperability of Cython's own implementations with Python's builtin types. To make this available in older Python versions, I created the backports_abc package for applications to use. Basically, you would install it and then say

import backports_abc
backports_abc.patch()

to get the Coroutine and Generator classes added to the collections.abc module if they are missing (i.e. in CPython versions before 3.5). This allows Cython to register its internal types with them and from that point on, any code using isinstance(x, Generator) or isinstance(x, Coroutine) will be able to support Cython's fast builtin types. If you find software packages that do not support this yet because they do type checks instead of ABC instance checks, please file a bug report with their projects to get them adapted. Twisted comes to mind, for example, or Tornado. [Update 2015-09-15]: The next Tornado release will have support for Cython coroutines.

CPython 3.5 itself has already been fixed up, thanks to Yury Selivanov, to natively support Cython implemented generators and coroutines. This allows asynchronous code (currently, but not limited to, asyncio) to take advantage of Cython's speed, which can easily be several times faster than Python coroutines in practice.

What else is there in Cython 0.23? Well, inlined generator expressions are back. This means that when you call builtin functions like any() or sorted() on a generator expression, Cython will inline its own (partial) implementation of that function into the generator implementation and avoid calling back and forth between the generator and its consumer. Instead, it will calculate the final result inside of the generator and only return it in one step at the very end. This can speed up the overall execution considerably.

Another feature that I invested some time into is faster numeric operations on Python's long (Py3 int) and float types. Arithmetic or shifting operations that involves integer or float constants are now faster because they avoid double unpacking of the operands and inline their constant parts.

On the C++ integration front, several minor issues have seen improvements and new standard declarations were added, which makes Cython 0.23 an even nicer and rounder tool for wrapping C++ code bases, or for making use of STL containers in Cython code. More C++ improvements are planned for the upcoming 0.24 release.

As usual, the complete list of features and fixes is much longer for such a large release. Hope you like it.

Line coverage analysis for Cython modules

The coverage analysis tool for Python has recently gained a plugin API that allows external tools to provide source code information. Cython has line tracing support since release 0.19, but the new API allows it to support coverage.py for line coverage reporting.

To test this, you need the latest developer versions of both coverage.py (pre-4.0) and Cython (post-0.22.0):

https://bitbucket.org/ned/coveragepy

https://github.com/cython/cython

Then, enable the Cython plugin in the .coveragerc config file of your project:

[run]
plugins = Cython.Coverage

And compile your Cython modules with line tracing support. This can be done by putting the following two comment lines at the top of the modules that you want to trace:

# cython: linetrace=True
# distutils: define_macros=CYTHON_TRACE=1

That's a double opt-in. The first line instructs Cython to generate verbose line tracing code (and thus increase the size of the resulting C/C++ file), and the second line enables this code at C compile time, which will most likely slow down your program. You can also configure both settings globally in your setup.py script, see the Cython documentation.

Then make sure you build your project in place (python setup.py build_ext --inplace) so that the generated C/C++ code files can be found right next to the binary modules and their sources.

That's it. Now your Cython modules should show up in your coverage reports. Any questions, bug reports or suggestions regarding this new feature can be discussed on the Cython-users mailing list.

Update: Coverage reporting is now also available for code that frees the GIL if the C macro CYTHON_TRACE_NOGIL=1 is set, i.e.:

# cython: linetrace=True
# distutils: define_macros=CYTHON_TRACE_NOGIL=1

All reporting formats of coverage.py are supported: plain text, XML and annotated HTML sources.