<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Stefans Welt (Posts about Cython)</title><link>http://blog.behnel.de/</link><description></description><atom:link href="http://blog.behnel.de/categories/cython.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><lastBuildDate>Mon, 04 Apr 2022 06:52:50 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Cython is 20!</title><link>http://blog.behnel.de/posts/cython-is-20/</link><dc:creator>Stefan Behnel</dc:creator><description>&lt;p&gt;Today, Cython celebrates its 20th anniversary!&lt;/p&gt;
&lt;p&gt;On April 4th, 2002, Greg Ewing published the
&lt;a class="reference external" href="https://mail.python.org/pipermail/python-list/2002-April/126661.html"&gt;first release of Pyrex 0.1&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Already at the time, it was invented and designed as a compiler that extended
the Python language with C data types to build extension modules for CPython.
A design that survived the last 20 years, and that made
&lt;a class="reference external" href="https://www.csse.canterbury.ac.nz/greg.ewing/python/Pyrex/"&gt;Pyrex&lt;/a&gt;,
and then &lt;a class="reference external" href="https://cython.org/"&gt;Cython&lt;/a&gt;,
a major corner stone of the Python data ecosystem.
And way beyond that.&lt;/p&gt;
&lt;p&gt;Now, on April 4th, 2022, its heir Cython is still very much alive and
serves easily hundreds of thousands of developers worldwide, day to day.&lt;/p&gt;
&lt;p&gt;I'm very grateful for Greg's ingenious invention at the time.
Let's look back at how we got to where we are today.&lt;/p&gt;
&lt;p&gt;I came to use Python around the time when Pyrex was first written.
Python had already been around for a dozen years,
&lt;a class="reference external" href="https://docs.python.org/3/whatsnew/2.2.html"&gt;version 2.2 was the latest&lt;/a&gt;,
and had brought us &lt;a class="reference external" href="https://www.python.org/download/releases/2.2.3/descrintro/"&gt;new style classes&lt;/a&gt;
which represented a major redesign of the type system,
as well as the iterator protocol and even generators,
which you had to enable with &lt;code class="docutils literal"&gt;from __future__ import generators&lt;/code&gt;,
because of potential conflicts with the new keyword &lt;code class="docutils literal"&gt;yield&lt;/code&gt;.
There weren't many times in Python's history when that was necessary.
Amongst the greatest Python releases of all times, that was one of them.&lt;/p&gt;
&lt;p&gt;Python 2.3 was in the makings, about to bring us another bunch of
&lt;a class="reference external" href="https://docs.python.org/3/whatsnew/2.3.html"&gt;cool new features&lt;/a&gt;
like &lt;code class="docutils literal"&gt;sum()&lt;/code&gt;, &lt;code class="docutils literal"&gt;enumerate()&lt;/code&gt; or sets as a data type in the standard library.&lt;/p&gt;
&lt;p&gt;CPython already had its reputation of providing a large standard library,
and a whole set of third-party packages that added another heap of functionality –
although Perl's &lt;a class="reference external" href="https://www.cpan.org/"&gt;CPAN&lt;/a&gt; would easily cover all of it in its mere shadow.
There was no &lt;code class="docutils literal"&gt;pip install&lt;/code&gt; anything at the time
(not even &lt;a class="reference external" href="http://peak.telecommunity.com/DevCenter/EasyInstall"&gt;easy_install&lt;/a&gt;),
no virtualenvs, no wheels
(and no &lt;a class="reference external" href="http://peak.telecommunity.com/DevCenter/PythonEggs"&gt;eggs&lt;/a&gt;), some form of binary
packages, but you'd mostly &lt;code class="docutils literal"&gt;python setup.py build&lt;/code&gt; your own software, especially on Linux.
Those were the days.&lt;/p&gt;
&lt;p&gt;Many of the binary third-party packages at the time were hand-written using the bare C-API.
There was &lt;a class="reference external" href="http://swig.org/"&gt;SWIG&lt;/a&gt; for generating C wrappers for lots of languages, including Python.
It worked, it was actually great to be able to generate multiple wrappers from a single source.
But they all looked mostly the same, and making them work and feel well for each of the language environments was hard to impossible.
And few people really needed wrappers for more than the one language they used.
So, lots of people used the C-API, and CPython had a reputation of being easily extensible in C – assuming you knew C well enough.
And more and more Python users didn't.&lt;/p&gt;
&lt;p&gt;In came Greg's idea of writing extension modules in Python.
Or in something that looked a lot like Python, with a few C-ish extensions.&lt;/p&gt;
&lt;p&gt;I don't know how he came up with the name Pyrex, which is a
&lt;a class="reference external" href="https://en.wikipedia.org/wiki/Pyrex"&gt;brand name&lt;/a&gt;
for thermal-resistant glass
(&lt;a class="reference external" href="https://en.wikipedia.org/wiki/Borosilicate_glass"&gt;originally invented here in Germany&lt;/a&gt; in 1893).
But Pyrex clearly hit a nerve at the time and grew very quickly.
Within weeks and months, there was support not only for functions but for extension types,
and for a growing number of Python language features.&lt;/p&gt;
&lt;p&gt;By the time I came to use Pyrex, it was already in a very attractive and feature rich state.
From the start, its unique selling point was to allow Python developers to write C code,
without having to write C code.
And that had made it the basis for large projects like &lt;a class="reference external" href="https://www.sagemath.org/"&gt;Sage&lt;/a&gt;,
for which it provided a critical software development infrastructure,
being the glue code between heaps of C/C++ math libraries and Python.&lt;/p&gt;
&lt;p&gt;In 2004, Martijn Faassen took on a project (and he's good at taking on projects)
of making XML in Python actually usable.
There was support before, there was &lt;a class="reference external" href="https://docs.python.org/3/library/xml.dom.minidom.html"&gt;minidom&lt;/a&gt;,
there was &lt;a class="reference external" href="http://pyxml.sourceforge.net/"&gt;PyXML&lt;/a&gt; with an extended feature set.
But many XML features of the time were missing, the tools were memory hungry and slow,
and the DOM-API was far from anything Python users would fall in love with.&lt;/p&gt;
&lt;p&gt;There was also a Python interface for &lt;a class="reference external" href="https://gitlab.gnome.org/GNOME/libxml2/-/wikis/home"&gt;libxml2&lt;/a&gt;,
a C library that covered a large part of the important XML technologies at the time.
With the caveat of mapping mostly its C-API to Python 1:1, and thus feeling excessively C-ish and
&lt;a class="reference external" href="https://web.archive.org/web/20110902041836/http://diveintomark.org/archives/2004/02/18/libxml2"&gt;exotic&lt;/a&gt;
to Python users, making it easy to trigger hard crashes at the same time.&lt;/p&gt;
&lt;p&gt;There was another alternative, though: &lt;a class="reference external" href="https://docs.python.org/3/library/xml.etree.elementtree.html"&gt;ElementTree&lt;/a&gt;,
designed by the recently deceased Fredrik Lundh (thanks for all the fish, Fredrik).
It was not in the standard library at the time, it only got adopted there in Python 2.5 (together with SQLite), one and a half years later.
It was an external package based on the &lt;a class="reference external" href="https://docs.python.org/3/library/pyexpat.html"&gt;pyexpat&lt;/a&gt; parser,
and it provided a lovely pythonic API for XML processing.
But with even less features than minidom.&lt;/p&gt;
&lt;p&gt;So, Martijn decided to bring it all together: the bunch of XML features from libxml2,
exposed in the pythonic, and already well established, interface of ElementTree.
And being a Python developer, wanting to design the interface from the Python point of view,
he chose Pyrex to implement that wrapper, and called it &lt;a class="reference external" href="https://lxml.de/"&gt;lxml&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I found the lxml project almost a year later, while looking for something that I could use as an extensible XML API.
I implemented some features for lxml to turn it into that, and along the way, made enhancements also to Pyrex.
Over the Pyrex mailing list, I got in touch with other developers who had their own more or less enhanced versions of Pyrex,
including &lt;a class="reference external" href="https://github.com/robertwb"&gt;Robert Bradshaw&lt;/a&gt;, one of the developers in the Sage project.
Eventually, in 2007, we decided to follow the example of the &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Apache_HTTP_Server"&gt;Apache web server&lt;/a&gt;
in bringing together the scattered bunch of existing Pyrex patches into a new project.
William Stein from the Sage project came up with a good name, and the infrastructure to maintain it –
github.com wasn't launched yet, and we used the &lt;a class="reference external" href="https://www.mercurial-scm.org/"&gt;Mercurial DVCS&lt;/a&gt;.
Thus, the Cython project was born.&lt;/p&gt;
&lt;p&gt;It was the beginning of a second, long success story.&lt;/p&gt;
&lt;p&gt;In the early years, William Stein was able to provide funding to the Cython project from Sage's resources,
given how important Cython was for the development of the Sage Math package.
Cython was an integral part of the Sage development sprints called &lt;a class="reference external" href="https://wiki.sagemath.org/dev1"&gt;Sage days&lt;/a&gt;.
We participated in Google's Summer of Code events that brought us in touch with
&lt;a class="reference external" href="https://github.com/dagss"&gt;Dag Sverre Seljebotn&lt;/a&gt; and
&lt;a class="reference external" href="https://github.com/markflorisson"&gt;Mark Florisson&lt;/a&gt;,
both of whom moved Cython's integration with NumPy and data processing forward in large steps.
And the Sage project also sponsored a workshop in München (where I was living at the time)
so that we were able to sit together in person,
for the first time, discussing, designing and building many great features in Cython,
as well as major advances in the coverage of (then) more recent Python language features,
in which Vitja Makarov played an important role.&lt;/p&gt;
&lt;p&gt;Over time, the &lt;a class="reference external" href="https://cython.org/#community"&gt;list of contributors&lt;/a&gt; to Cython grew longer and longer,
from large feature additions to small bug fixes and helpful documentation improvements.
In 2008, me and &lt;a class="reference external" href="https://github.com/dalcinl"&gt;Lisandro Dalcín&lt;/a&gt;
implemented support for Python 3.0 before it was even released,
just like Pyrex and Cython have followed CPython's development ever since they existed,
allowing users to easily adapt their extension modules to various C-API changes across (C)Python releases.
And in the other direction, some of the optimisations that CPython's own internal code generation tool
&lt;a class="reference external" href="https://github.com/python/cpython/tree/main/Tools/clinic"&gt;argument clinic&lt;/a&gt;
employs for fast Python function argument parsing, were adopted from Cython.&lt;/p&gt;
&lt;p&gt;I remember discussions and cooperations with the CPython developers &lt;a class="reference external" href="https://github.com/1st1"&gt;Yury Selivanov&lt;/a&gt;
on async features and with &lt;a class="reference external" href="https://github.com/vstinner"&gt;Victor Stinner&lt;/a&gt;, &lt;a class="reference external" href="https://github.com/encukou"&gt;Petr Viktorin&lt;/a&gt;
or &lt;a class="reference external" href="https://github.com/ncoghlan"&gt;Nick Coghlan&lt;/a&gt; on Python C-API topics.
Several PyPy developers, including &lt;a class="reference external" href="https://github.com/rlamy"&gt;Ronan Lamy&lt;/a&gt; and &lt;a class="reference external" href="https://github.com/mattip/"&gt;Matti Picus&lt;/a&gt;,
have helped in word and code to improve the integration and stability between both tools.
The exchange with people from large and impactful projects like
&lt;a class="reference external" href="https://numpy.org/"&gt;NumPy&lt;/a&gt;, &lt;a class="reference external" href="https://pandas.pydata.org/"&gt;Pandas&lt;/a&gt; and the &lt;code class="docutils literal"&gt;&lt;span class="pre"&gt;scikit-*&lt;/span&gt;&lt;/code&gt; family of tools
has always helped moving Cython in a user centric direction,
while giving me a warm feeling that it truly enables its users to get their work done.
And the emergence of complementary tools like
&lt;a class="reference external" href="https://pybind11.readthedocs.io/en/stable/index.html"&gt;pybind11&lt;/a&gt; or
&lt;a class="reference external" href="https://numba.pydata.org/"&gt;Numba&lt;/a&gt;
has helped to diversify the choices throughout the ecosystem in which Cython resides,
while only broadening the field without reducing the impact that the language and compiler has for its users.&lt;/p&gt;
&lt;p&gt;Today, after 20 years of development, Cython is a modern programming language,
embedded in the Python language rather than the other way round,
but still extending it with C/C++ super powers.&lt;/p&gt;
&lt;p&gt;We helped our users help their users through many exciting endeavours along the way,
&lt;a class="reference external" href="https://numpy.org/case-studies/blackhole-image/"&gt;taking pictures of black holes&lt;/a&gt;,
&lt;a class="reference external" href="https://learnpython.com/blog/python-on-mars/"&gt;sending robots to Mars&lt;/a&gt;,
&lt;a class="reference external" href="https://www.youtube.com/watch?v=_1MSX7V28Po"&gt;scaling up Django websites to a thousand million users&lt;/a&gt;,
&lt;a class="reference external" href="https://climt.readthedocs.io/en/latest/"&gt;building climate models&lt;/a&gt;,
analysing, processing and &lt;a class="reference external" href="https://scikit-learn.org/"&gt;machine learning&lt;/a&gt; of
&lt;a class="reference external" href="https://spacy.io/"&gt;human text&lt;/a&gt;,
&lt;a class="reference external" href="https://scikit-image.org/"&gt;real world images&lt;/a&gt;,
and &lt;a class="reference external" href="https://pandas.pydata.org/"&gt;other data from countless areas&lt;/a&gt;,
be it scientific, financial, economic, ecologic or probably any other type of data from small to large scale.&lt;/p&gt;
&lt;p&gt;I'm proud and happy to see how far Cython has come from its early beginnings.
And I'm excited to continue seeing where it will go from here.&lt;/p&gt;
&lt;p&gt;So, from New Zealand, from Europe and the Americas, from Asia, Australia and Africa,
to anywhere on Earth, and maybe Mars…&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Happy anniversary, Cython!&lt;/p&gt;
&lt;/blockquote&gt;</description><category>Cython</category><category>english</category><category>Planet Python</category><category>Python</category><guid>http://blog.behnel.de/posts/cython-is-20/</guid><pubDate>Mon, 04 Apr 2022 06:52:37 GMT</pubDate></item><item><title>Should you ship the Cython generated C code or not?</title><link>http://blog.behnel.de/posts/ship-generated-c-code-or-not/</link><dc:creator>Stefan Behnel</dc:creator><description>&lt;p&gt;When you use &lt;a class="reference external" href="https://cython.org/"&gt;Cython&lt;/a&gt; for your Python extensions (not if, when ;-)), there are different opinions on whether you should generate the C code locally and ship it in your sdist source packages on PyPI, or you should make Cython a build-time dependency for your package and let users run it on their side.&lt;/p&gt;
&lt;p&gt;Both approaches have their pros and cons, but I personally recommend generating the C code on the maintainer side and then shipping it in sdists. Here is a bit of an explanation to help you with your own judgement.&lt;/p&gt;
&lt;p&gt;The C code that Cython generates is deterministic and very intentionally adaptive to where you C-compile it. We work hard to do all environment specific adaptations (Python version, C compiler, …) in the C code and not in the code generator that creates it. It's the holy cow of "generate once, compile everywhere". And that's one of the main selling points of Cython, we write C so you don't have to. But obviously, once the C code is generated, it cannot take as-of-now unknown future environmental changes into account any more, such as changes to the CPython C-API, which we only cover in newer Cython releases.&lt;/p&gt;
&lt;p&gt;Because the C code is deterministic, making Cython a build time dependency and then pinning an &lt;em&gt;exact&lt;/em&gt; Cython version with it is entirely useless, because you can just generate the exact same C code on your side once and ship it. One dependency less, lots of user side complexity avoided. So, the only case we're talking about here is allowing different (usually newer) Cython versions to build your code.&lt;/p&gt;
&lt;p&gt;If you ship the C file, then you know what you get and you don't depend on whatever Cython version users have installed on their side. You avoid the maintenance burden of having to respond to bug reports for seemingly unrelated C code lines or bugs in certain Cython versions (which users will rarely mention in their bug reports).&lt;/p&gt;
&lt;p&gt;If, instead, you use a recent Cython version at package build time, then you avoid bit rot in the generated C code, but you risk build failures on user side due to users having a buggy Cython version installed (which may not have existed when you shipped the package, so you couldn't exclude it from the dependency range). Or your code may fail to compile with a freshly released Cython due to incompatible language changes in the new version. However, if those (somewhat exceptional) cases don't happen, then you may end up with a setting in which your code adapts also to newer environments, by using a recent Cython version automatically and generated C code that already knows about the new environment. That is definitely an advantage.&lt;/p&gt;
&lt;p&gt;Basically, for maintained packages, I consider shipping the generated C code the right way. Less hassle, easier debugging, better user experience. For unmaintained packages, regenerating the C code at build time &lt;em&gt;can&lt;/em&gt; extend the lifetime of the package to newer environments for as long as it does not run into failures due to incompatible Cython compiler changes (so you trade one compatibility level for another one).&lt;/p&gt;
&lt;p&gt;The question is whether the point at which a package becomes unmaintained can ever be clear enough to make the switch. Regardless of which way you choose, as with all code out there, at some point in the future someone will have to do something, either to your package/code or to your build setup, in order to prevent fatal bit rot. But using Cython in the first place should at least ease the pain of getting over that point when it occurs.&lt;/p&gt;</description><category>Cython</category><category>english</category><category>Planet Python</category><category>Python</category><guid>http://blog.behnel.de/posts/ship-generated-c-code-or-not/</guid><pubDate>Mon, 22 Jun 2020 09:11:11 GMT</pubDate></item><item><title>My responses to a Cython dev interview</title><link>http://blog.behnel.de/posts/my-responses-to-a-cython-dev-interview/</link><dc:creator>Stefan Behnel</dc:creator><description>&lt;p&gt;I recently received a request for an online interview by Jonathan Ruiz, a CS student in Berlin.
He's implementing graph algorithms as part of his final Bachelor thesis, and was evaluating and using Cython to get performance improvements.
During his work, he thought it'd be nice to get some comments from a Cython core dev and sent me a couple of questions.
Here's what I answered.&lt;/p&gt;
&lt;ol class="arabic"&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;First of all, thank you Stefan for your time in this difficult situation.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Thanks for asking me.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;How did your interest in programming and then compilers begin?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I have a pretty straight forward background and education in computer science and software development.
But I'm not a compiler expert. In fact, I'm not even working on a compiler in the true sense.
I'm working on Cython, which is a source code translator and code generator. The actual native code generation is then left to a C compiler.
However, we avoid that distinction ourselves in the project because in the end, people use Cython to compile Python down to native code.
So the distinction is more of an implementation detail.&lt;/p&gt;
&lt;p&gt;I came to Cython through a bit of a diversion.
I needed a Python XML library for the proof-of-concept implementation of my doctor's thesis somewhere around 2005.
Not so long before that, Martijn Faassen had started writing an ElementTree-like wrapper for the XML library libxml2, called lxml,
which had several features that I needed and was easy enough for me to hack on to get the features implemented that I was missing.&lt;/p&gt;
&lt;p&gt;lxml was written in a code generator called Pyrex, and I ended up implementing a couple of features in that code generator that helped me in my work on lxml.
Not all of these changes were accepted upstream, at least not in a timely fashion, and at some point I found that others had that problem, too, and had ended up with their own long-term forks.
Together with Robert Bradshaw and William Stein from the University of Washington in Seattle, USA, we decided to fork Pyrex for good, and start a new official project, which we named Cython.
That was in 2007, and I've worked on the Cython project ever since.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;What advice would you give to students who want to break into this field?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Read code.
Seriously.
There is a lot that you can learn at a university about algorithms,
about smart ideas that people came up with,
about ways to tell and decide what's smart and what isn't,
about the way things work (and should work) in general.
A CS degree is an excellent way to set a basis for your future software design endeavours.&lt;/p&gt;
&lt;p&gt;But there's nothing that comes close to reading other people's code when you're trying to understand how things work in real life and why the tools at hand don't do what you want them to do.
And then fixing them to do it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Which branches of mathematics do you think are important to become
a good programmer or what particularly benefited you in Cython optimisation, for example?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I would love to say that my math education at university helped me here and there,
but in retrospect, I need to admit that I could have come to the same point where I stand now with just my math lessons at school (although those were pretty decent, I guess).
I would claim that statistics are surprisingly important in real life and software development, and are not always taught deeply enough at school (nor in CS studies), IMHO.
Even just the understanding that the result of a benchmark run is just a single value in a cloud of scattered results really helps putting those numbers in context in your head.&lt;/p&gt;
&lt;p&gt;There are definitely fields in software development in which math is more helpful than in the fields I've touched mostly. Graphics comes to mind, for example.
But I think what's much more important than a math education is the ability to read and learn, and to be curious of the work of others.
Because these days, 95+% of our software development work is based on what others have already done before us (and for us).
Use existing tools, learn how they work and what their limits are, and then extend those limits when you need to.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;If I'm not mistaken, since April 2019 you have also been a core developer in CPython: what responsibilities does this position entail?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The main (and most obvious) difference is the ability to click the green merge button on github. :)
Seriously, you can do a lot of great work in a project without ever clicking that button.
You can create tickets, investigate bugs, write documentation, recommend cool projects to others, help people use them, participate in design discussions, write feature pull requests.
You can move a project truly forward without being a "core developer".
But once you have the merge right, you are taking over the responsibility for the code that you merge by clicking that button, wherever that code came from.
If that code unexpectedly breaks someone's computer at the end of the world, you are the one who has to fix it, somehow. Even just by reverting the merge, but you have to do something.
That changes your perspective on that piece of code a lot. Even if the author is you.&lt;/p&gt;
&lt;p&gt;Being a core developer in a project is really more of an obligation than an honour.
But it can also give you a better standing in a project, because others can see that you are taking responsibility for it.
So it comes with a bit of a social status, too.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Cython has been and is a key tool in scientific projects, such as the Event Horizon Telescope.
Which scientific libraries are you missing in Cython right now? Are there any special ones that you are working on?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I'm not working on scientific libraries myself, although I know a lot of people from other projects in the field.
I'm not missing anything here, personally. :)&lt;/p&gt;
&lt;p&gt;OTOH, I like hearing about things that others do with Cython.
And I like to help others to make Cython do great things for them.&lt;/p&gt;
&lt;p&gt;The really cool thing about OpenSource software development is that I'm creating "eternal" values every day.
Whatever I write today may end up helping some person on the other side of the planet, or next door, to invent something cool,
to answer the last questions about life, the universe and everything, to save the world or someone else's life.
That's their projects, their ideas and their work, but it's the software that I am writing together with lots of other people that helps them get their work done.
And that is a great feeling.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Are there any important features that you would like to implement in Cython in the future?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The issue tracker has more than 740 open tickets right now. :)
But that answer misses the point.
I think the most important goal is to keep helping users getting unstuck when they run into something that they can't really (or easily) solve themselves.
Or to help them fix their own problems in a way that more people can benefit from.
Cython is a tool for others to use for their own needs. It should continue to achieve that.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;How do you see Cython ten years from now?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I never liked that question when interviewing dev candidates, and I'm not going to answer it now. ;-)
Ten years is about 10-20% of a human's total lifetime. And it's half of an eternity in Tech. It's a &lt;em&gt;very&lt;/em&gt; long time.
I like how Niels Bohr (supposedly) put it: "predictions are hard to make, especially about the future".&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Thank you very much again for your time, Stefan. Take good care of yourself.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Have fun and stay safe.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;</description><category>Cython</category><category>english</category><category>Planet Python</category><category>Python</category><guid>http://blog.behnel.de/posts/my-responses-to-a-cython-dev-interview/</guid><pubDate>Thu, 16 Apr 2020 10:46:20 GMT</pubDate></item><item><title>Speeding up basic object operations in Cython</title><link>http://blog.behnel.de/posts/tuning-basic-object-operations-in-cython/</link><dc:creator>Stefan Behnel</dc:creator><description>&lt;p&gt;Raymond Hettinger published a nice little &lt;a class="reference external" href="https://github.com/python/cpython/blob/master/Tools/scripts/var_access_benchmark.py"&gt;micro-benchmark script&lt;/a&gt; for comparing basic operations like attribute or item access in CPython and comparing the performance across Python versions.
Unsurprisingly, Cython performs quite well in comparison to the latest CPython 3.8-pre development version, executing most operations 30-50% faster.
But the script allowed me to tune some more performance out of certain less well performing operations.
The timings are shown below, first those for CPython 3.8-pre as a baseline, then (for comparison) the Cython timings with all optimisations disabled that can be controlled by C macros (&lt;code class="docutils literal"&gt;gcc &lt;span class="pre"&gt;-DCYTHON_...=0&lt;/span&gt;&lt;/code&gt;), the normal (optimised) Cython timings, and the now improved version at the end.&lt;/p&gt;
&lt;table&gt;
&lt;colgroup&gt;
&lt;col style="width: 31%"&gt;
&lt;col style="width: 17%"&gt;
&lt;col style="width: 17%"&gt;
&lt;col style="width: 17%"&gt;
&lt;col style="width: 17%"&gt;
&lt;/colgroup&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th class="head"&gt;&lt;!--  --&gt;
&lt;/th&gt;
&lt;th class="head"&gt;&lt;p&gt;CPython 3.8 (pre)&lt;/p&gt;&lt;/th&gt;
&lt;th class="head"&gt;&lt;p&gt;Cython 3.0  (no opt)&lt;/p&gt;&lt;/th&gt;
&lt;th class="head"&gt;&lt;p&gt;Cython 3.0 (pre)&lt;/p&gt;&lt;/th&gt;
&lt;th class="head"&gt;&lt;p&gt;Cython 3.0 (tuned)&lt;/p&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;p&gt;Variable and attribute read access:&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;  read_local&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            5.5 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            0.2 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            0.2 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            0.2 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;  read_nonlocal&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            6.0 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            0.2 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            0.2 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            0.2 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;  read_global&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           17.9 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           13.3 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            2.2 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            2.2 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;  read_builtin&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           21.0 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            0.2 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            0.2 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            0.1 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;  read_classvar_from_class&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           23.7 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           16.1 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           14.1 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           14.1 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;  read_classvar_from_instance&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           20.9 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           11.9 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           11.2 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           11.0 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;  read_instancevar&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           31.7 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           22.3 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           20.8 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           22.0 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;  read_instancevar_slots&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           25.8 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           16.5 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           15.3 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           17.0 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;  read_namedtuple&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           23.6 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           16.2 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           13.9 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           13.5 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;  read_boundmethod&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           32.5 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           23.4 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           22.2 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           21.6 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;p&gt;Variable and attribute write access:&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;  write_local&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            6.4 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            0.2 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            0.1 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            0.1 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;  write_nonlocal&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            6.8 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            0.2 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            0.1 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            0.1 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;  write_global&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           22.2 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           13.2 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           13.7 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           13.0 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;  write_classvar&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;          114.2 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;          103.2 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;          113.9 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           94.7 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;  write_instancevar&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           49.1 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           34.9 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           28.6 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           29.8 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;  write_instancevar_slots&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           33.4 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           22.6 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           16.7 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           17.8 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;p&gt;Data structure read access:&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;  read_list&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           23.1 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            5.5 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            4.0 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            4.1 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;  read_deque&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           24.0 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            5.7 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            4.3 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            4.4 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;  read_dict&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           28.7 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           21.2 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           16.5 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           16.5 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;  read_strdict&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           23.3 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           10.7 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           10.5 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           12.0 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;p&gt;Data structure write access:&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;  write_list&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           28.0 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            8.2 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            4.3 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            4.2 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;  write_deque&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           29.5 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            8.2 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            6.3 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            6.4 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;  write_dict&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           32.9 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           24.0 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           21.7 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           22.6 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;  write_strdict&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           29.2 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           16.4 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           15.8 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           16.0 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;p&gt;Stack (or queue) operations:&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;  list_append_pop&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           63.6 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           67.9 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           20.6 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           20.5 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;  deque_append_pop&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           56.0 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           81.5 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;          159.3 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           46.0 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;  deque_append_popleft&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           58.0 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           56.2 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           88.1 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;           36.4 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;p&gt;Timing loop overhead:&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;  loop_overhead&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            0.4 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            0.2 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            0.1 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;div class="line-block"&gt;
&lt;div class="line"&gt;            0.2 ns&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Some things that are worth noting:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;There is always a bit of variance across the runs, so don't get excited about a couple of percent difference.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The read/write access to local variables is not reasonably measurable in Cython since it uses local/global C variables, and the C compiler discards any useless access to them.  But don't worry, they are really fast.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Builtins (and module global variables in Py3.6+) are cached, which explains the "close to nothing" timings for them above.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Even with several optimisations disabled, Cython code is still visibly faster than CPython.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code class="docutils literal"&gt;write_classvar&lt;/code&gt; benchmark revealed a performance problem in CPython that is being &lt;a class="reference external" href="https://bugs.python.org/issue36012"&gt;worked on&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code class="docutils literal"&gt;deque&lt;/code&gt; related benchmarks revealed performance problems in Cython that are &lt;a class="reference external" href="https://github.com/cython/cython/issues/2850"&gt;now fixed&lt;/a&gt;, as you can see in the last column.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;</description><category>Cython</category><category>english</category><category>Planet Python</category><category>Python</category><guid>http://blog.behnel.de/posts/tuning-basic-object-operations-in-cython/</guid><pubDate>Sun, 17 Feb 2019 18:24:48 GMT</pubDate></item><item><title>What's new in Cython 0.29?</title><link>http://blog.behnel.de/posts/whats-new-in-cython-029/</link><dc:creator>Stefan Behnel</dc:creator><description>&lt;p&gt;I'm happy to announce the release of &lt;a class="reference external" href="https://cython.org"&gt;Cython&lt;/a&gt; 0.29.
In case you didn't hear about Cython before, it's the most widely used statically optimising Python compiler out there.
It translates Python (2/3) code to C, and makes it as easy as Python itself to tune the code all the way down into fast native code.
This time, we added several new features that help with speeding up and parallelising regular Python code to escape from the limitations of the GIL.&lt;/p&gt;
&lt;p&gt;So, what exactly makes this another great Cython release?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The contributors&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;First of all, our contributors.
A substantial part of the &lt;a class="reference external" href="https://github.com/cython/cython/blob/release/CHANGES.rst"&gt;changes in this release&lt;/a&gt; was written by users and non-core developers and contributed via pull requests.
A big "Thank You!" to all of our contributors and bug reporters!
You really made this a great release.&lt;/p&gt;
&lt;p&gt;Above all, Gabriel de Marmiesse has invested a remarkable amount of time into restructuring and rewriting the documentation.
It now has a lot less historic smell, and much better, tested (!) code examples.
And he obviously found more than one problematic piece of code in the docs that we were able to fix along the way.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cython 3.0&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;And this will be the last 0.x release of Cython.
The Cython compiler has been in production critical use for years, all over the world, and there is really no good reason for it to have an 0.x version scheme.
In fact, the 0.x release series can easily be counted as 1.x, which is one of the reasons why we now decided to skip the 1.x series all together.
And, while we're at it, why not the 2.x prefix as well.
Shift the decimals of 0.29 a bit to the left, and then the next release will be 3.0.
The main reason for that is that we want 3.0 to do two things: a) switch the default language compatibility level from Python 2.x to 3.x and b) break with some backwards compatibility issues that get more in the way than they help.
We have started collecting a &lt;a class="reference external" href="https://github.com/cython/cython/milestone/58"&gt;list of things to rethink and change&lt;/a&gt; in our bug tracker.&lt;/p&gt;
&lt;p&gt;Turning the language level switch is a tiny code change for us, but a larger change for our users and the millions of source lines in their code bases.
In order to avoid any resemblance with the years of effort that went into the Py2/3 switch, we took measures that allow users to choose how much effort they want to invest, from "almost none at all" to "as much as they want".&lt;/p&gt;
&lt;p&gt;Cython has a long tradition of helping users adapt their code for both Python 2 and Python 3, ever since we ported it to Python 3.0.
We used to joke back in 2008 that Cython was the easiest way to migrate an existing Py2 code base to Python 3, and it was never really meant as a joke.
Many annoying details are handled internally in the compiler, such as the &lt;code class="docutils literal"&gt;range&lt;/code&gt; versus &lt;code class="docutils literal"&gt;xrange&lt;/code&gt; renaming, or dict iteration.
Cython has supported dict and set comprehensions before they were backported to Py2.7, and has long provided &lt;a class="reference external" href="http://docs.cython.org/en/latest/src/tutorial/strings.html#python-string-types-in-cython-code"&gt;three string types&lt;/a&gt; (or four, if you want) instead of two.
It distinguishes between &lt;code class="docutils literal"&gt;bytes&lt;/code&gt;, &lt;code class="docutils literal"&gt;str&lt;/code&gt; and &lt;code class="docutils literal"&gt;unicode&lt;/code&gt; (and it knows &lt;code class="docutils literal"&gt;basestring&lt;/code&gt;), where &lt;code class="docutils literal"&gt;str&lt;/code&gt; is the type that changes between Py2's bytes &lt;code class="docutils literal"&gt;str&lt;/code&gt; and Py3's Unicode &lt;code class="docutils literal"&gt;str&lt;/code&gt;.
This distinction helps users to be explicit, even at the C level, what kind of character or byte sequence they want, and how it should behave across the Py2/3 boundary.&lt;/p&gt;
&lt;p&gt;For Cython 3.0, we plan to switch only the default language level, which users can always change via a command line option or the compiler directive &lt;code class="docutils literal"&gt;language_level&lt;/code&gt;.
To be clear, Cython will continue to support the existing language semantics.
They will just no longer be the default, and users have to select them explicitly by setting &lt;code class="docutils literal"&gt;language_level=2&lt;/code&gt;.
That's the "almost none at all" case.
In order to prepare the switch to Python 3 language semantics by default, Cython now issues a warning when no language level is explicitly requested, and thus pushes users into being explicit about what semantics their code requires.
We obviously hope that many of our users will take the opportunity and migrate their code to the nicer Python 3 semantics, which Cython has long supported as &lt;code class="docutils literal"&gt;language_level=3&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;But we added something even better, so let's see what the current release has to offer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A new language-level&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Cython 0.29 supports a new setting for the &lt;code class="docutils literal"&gt;language_level&lt;/code&gt; directive, &lt;code class="docutils literal"&gt;language_level=3str&lt;/code&gt;, which will become the new default language level in Cython 3.0.
We already added it now, so that users can opt in and benefit from it right away, and already prepare their code for the coming change.
It's an "in between" kind of setting, which enables all the nice Python 3 goodies that are not syntax compatible with Python 2.x, but without requiring all unprefixed string literals to become Unicode strings when the compiled code runs in Python 2.x.
This was one of the biggest problems in the general Py3 migration.
And in the context of Cython's integration with C code, it got in the way of our users even a bit more than it would in Python code.
Our goals are to make it easy for new users who come from Python 3 to compile their code with Cython and to allow existing (Cython/Python 2) code bases to make use of the benefits before they can make a 100% switch.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Module initialisation like Python does&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;One great change under the hood is that we managed to enable the &lt;a class="reference external" href="https://www.python.org/dev/peps/pep-0489/"&gt;PEP-489&lt;/a&gt; support (again).
It was already mostly available in Cython 0.27, but lead to problems that made us back-pedal at the time.
Now we believe that we found a way to bring the saner module initialisation of Python 3.5 to our users, without risking the previous breakage.
Most importantly, features like subinterpreter support or module reloading are detected and disabled, so that Cython compiled extension modules cannot be mistreated in such environments.
Actual support for these little used features will probably come at some point, but will certainly require an opt-in of the users, since it is expected to reduce the overall performance of Python operations quite visibly.
The more important features like a correct &lt;code class="docutils literal"&gt;__file__&lt;/code&gt; path being available at import time, and in fact, extension modules looking and behaving exactly like Python modules during the import, are much more helpful to most users.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Compiling plain Python code with OpenMP and memory views&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Another PEP is worth mentioning next, actually two PEPs: &lt;a class="reference external" href="https://www.python.org/dev/peps/pep-0484/"&gt;484&lt;/a&gt; and &lt;a class="reference external" href="https://www.python.org/dev/peps/pep-0526/"&gt;526&lt;/a&gt;, vulgo type annotations.
Cython has supported type declarations in Python code for years, has switched to PEP-484/526 compatible typing with release 0.27 (more than one year ago), and has now gained several new features that make static typing in Python code much more widely usable.
Users can now declare their statically typed Python functions as not requiring the GIL, and thus call them from a parallel OpenMP loops and parallel Python threads, all without leaving Python code compatibility.
Even exceptions can now be raised directly from thread-parallel code, without first having to acquire the GIL explicitly.&lt;/p&gt;
&lt;p&gt;And memory views are available in Python typing notation:&lt;/p&gt;
&lt;pre class="code cython"&gt;&lt;a id="rest_code_ec42589c41414bdaa055c1b339dd28e2-1" name="rest_code_ec42589c41414bdaa055c1b339dd28e2-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;cython&lt;/span&gt;
&lt;a id="rest_code_ec42589c41414bdaa055c1b339dd28e2-2" name="rest_code_ec42589c41414bdaa055c1b339dd28e2-2"&gt;&lt;/a&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;cython.parallel&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="n"&gt;prange&lt;/span&gt;
&lt;a id="rest_code_ec42589c41414bdaa055c1b339dd28e2-3" name="rest_code_ec42589c41414bdaa055c1b339dd28e2-3"&gt;&lt;/a&gt;
&lt;a id="rest_code_ec42589c41414bdaa055c1b339dd28e2-4" name="rest_code_ec42589c41414bdaa055c1b339dd28e2-4"&gt;&lt;/a&gt;&lt;span class="nd"&gt;@cython&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cfunc&lt;/span&gt;
&lt;a id="rest_code_ec42589c41414bdaa055c1b339dd28e2-5" name="rest_code_ec42589c41414bdaa055c1b339dd28e2-5"&gt;&lt;/a&gt;&lt;span class="nd"&gt;@cython&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;nogil&lt;/span&gt;
&lt;a id="rest_code_ec42589c41414bdaa055c1b339dd28e2-6" name="rest_code_ec42589c41414bdaa055c1b339dd28e2-6"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;compute_one_row&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cython&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;double&lt;/span&gt;&lt;span class="p"&gt;[:])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;cython&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_ec42589c41414bdaa055c1b339dd28e2-7" name="rest_code_ec42589c41414bdaa055c1b339dd28e2-7"&gt;&lt;/a&gt;    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;a id="rest_code_ec42589c41414bdaa055c1b339dd28e2-8" name="rest_code_ec42589c41414bdaa055c1b339dd28e2-8"&gt;&lt;/a&gt;
&lt;a id="rest_code_ec42589c41414bdaa055c1b339dd28e2-9" name="rest_code_ec42589c41414bdaa055c1b339dd28e2-9"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process_2d_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cython&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;double&lt;/span&gt;&lt;span class="p"&gt;[:,:]):&lt;/span&gt;
&lt;a id="rest_code_ec42589c41414bdaa055c1b339dd28e2-10" name="rest_code_ec42589c41414bdaa055c1b339dd28e2-10"&gt;&lt;/a&gt;    &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cython&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Py_ssize_t&lt;/span&gt;
&lt;a id="rest_code_ec42589c41414bdaa055c1b339dd28e2-11" name="rest_code_ec42589c41414bdaa055c1b339dd28e2-11"&gt;&lt;/a&gt;
&lt;a id="rest_code_ec42589c41414bdaa055c1b339dd28e2-12" name="rest_code_ec42589c41414bdaa055c1b339dd28e2-12"&gt;&lt;/a&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;prange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;num_threads&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;nogil&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_ec42589c41414bdaa055c1b339dd28e2-13" name="rest_code_ec42589c41414bdaa055c1b339dd28e2-13"&gt;&lt;/a&gt;        &lt;span class="n"&gt;compute_one_row&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/pre&gt;&lt;p&gt;This code will work with NumPy arrays when run in Python, and with any data provider that supports the &lt;a class="reference external" href="https://www.python.org/dev/peps/pep-3118/"&gt;Python buffer interface&lt;/a&gt; when compiled with Cython.
As a compiled extension module, it will execute at full C speed, in parallel, with 16 OpenMP threads, as requested by the &lt;code class="docutils literal"&gt;prange()&lt;/code&gt; loop.
As a normal Python module, it will support all the great Python tools for code analysis, test coverage reporting, debugging, and what not.
Although Cython also has direct support for a couple of those by now.
Profiling (with &lt;code class="docutils literal"&gt;cProfile&lt;/code&gt;) and coverage analysis (with &lt;code class="docutils literal"&gt;coverage.py&lt;/code&gt;) have been around for several releases, for example.
But debugging a Python module in the interpreter is obviously still much easier than debugging a native extension module, with all the edit-compile-run cycle overhead.&lt;/p&gt;
&lt;p&gt;Cython's support for compiling pure Python code combines the best of both worlds: native C speed, and easy Python code development, with full support for all the great Python 3.7 language features, even if you still need your (compiled) code to run in Python 2.7.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;More speed&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Several improvements make use of the dict versioning that was introduced in CPython 3.6.
It allows module global names to be looked up much faster, close to the speed of static C globals.
Also, the attribute lookup for calls to &lt;code class="docutils literal"&gt;cpdef&lt;/code&gt; methods (C methods with Python wrappers) can benefit a lot, it can become up to 4x faster.&lt;/p&gt;
&lt;p&gt;Constant tuples and slices are now deduplicated and only created once at module init time.
Especially with common slices like &lt;code class="docutils literal"&gt;[1:]&lt;/code&gt; or &lt;code class="docutils literal"&gt;&lt;span class="pre"&gt;[::-1]&lt;/span&gt;&lt;/code&gt;, this can reduce the amount of one-time initialiation code in the generated extension modules.&lt;/p&gt;
&lt;p&gt;The &lt;a class="reference external" href="https://github.com/cython/cython/blob/release/CHANGES.rst"&gt;changelog&lt;/a&gt; lists several other optimisations and improvements.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Many important bug fixes&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We've had a hard time following a &lt;a class="reference external" href="https://bugs.python.org/issue25612"&gt;change in CPython 3.7&lt;/a&gt; that "broke the world", as Mark Shannon put it.
It was meant as a mostly internal change on their side that improved the handling of exceptions inside of generators, but it turned out to break all extension modules out there that were built with Cython, and then some.
A minimal fix was already released in Cython 0.28.4, but 0.29 brings complete support for the new generator exception stack in CPython 3.7, which allows exceptions raised or handled by Cython implemented generators to interact correctly with CPython's own generators.
Upgrading is therefore warmly recommended for better CPython 3.7 support.
As usual with Cython, translating your existing code with the new release will make it benefit from the new features, improvements and fixes.&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="http://www.stackless.com/"&gt;Stackless Python&lt;/a&gt; has not been a big focus for Cython development so far, but the developers noticed a problem with Cython modules earlier this year.
Normally, they try to keep Stackless binary compatible with CPython, but there are corner cases where this is not possible (specifically frames), and one of these broke the compatibility with Cython compiled modules.
Cython 0.29 now contains a fix that makes it play nicely with Stackless 3.x.&lt;/p&gt;
&lt;p&gt;A funny bug that is worth noting is a mysteriously disappearing string multiplier in earlier Cython versions.
A constant expression like &lt;cite&gt;"x" * 5&lt;/cite&gt; results in the string &lt;cite&gt;"xxxxx"&lt;/cite&gt;, but &lt;cite&gt;"x" * 5 + "y"&lt;/cite&gt; becomes &lt;cite&gt;"xy"&lt;/cite&gt;.
Apparently not a common code construct, since no user ever complained about it.&lt;/p&gt;
&lt;p&gt;Long-time users of Cython and NumPy will be happy to hear that Cython's memory views are now API-1.7 clean, which means that they can get rid of the annoying "&lt;code class="docutils literal"&gt;Using deprecated NumPy API&lt;/code&gt;" warnings in the C compiler output.
Simply append the C macro definition &lt;code class="docutils literal"&gt;("NPY_NO_DEPRECATED_API", "NPY_1_7_API_VERSION")&lt;/code&gt; to the macro setup of your distutils extensions in &lt;code class="docutils literal"&gt;setup.py&lt;/code&gt; to make them disappear.
Note that this does not apply to the old low-level &lt;code class="docutils literal"&gt;&lt;span class="pre"&gt;ndarray[...]&lt;/span&gt;&lt;/code&gt; syntax, which exposes several deprecated internals of the NumPy C-API that are not easy to replace.
Memory views are a fast high-level abstraction that does not rely specifically on NumPy and therefore does not suffer from these API constraints.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Less compilation :)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;And finally, as if to make a point that static compilation is a great tool but not always a good idea, we decided to reduce the number of modules that Cython compiles of itself from 13 down to 8, thus keeping 5 more modules normally interpreted by Python.
This makes the compiler runs about 5-7% slower, but reduces the packaged size and the installed binary size by about half, thus reducing download times in CI builds and virtualenv creations.
Python is a very efficient language when it comes to functionality per line of code, and its byte code is similarly high-level and efficient.
Compiled native code is a lot larger and more verbose in comparison, and this can easily make a difference of megabytes of shared libraries versus kilobytes of Python modules.&lt;/p&gt;
&lt;p&gt;We therefore repeat our recommendation to focus Cython's usage on the major pain points in your application, on the critical code sections that a profiler has pointed you at.
The ability to compile those, and to tune them at the C level, is what makes Cython such a great and versatile tool.&lt;/p&gt;</description><category>Cython</category><category>english</category><category>Planet Python</category><category>Python</category><guid>http://blog.behnel.de/posts/whats-new-in-cython-029/</guid><pubDate>Sun, 14 Oct 2018 16:11:05 GMT</pubDate></item><item><title>Cython, pybind11, cffi – which tool should you choose?</title><link>http://blog.behnel.de/posts/cython-pybind11-cffi-which-tool-to-choose/</link><dc:creator>Stefan Behnel</dc:creator><description>&lt;p&gt;In and after the conference talks that I give about &lt;a class="reference external" href="http://cython.org/"&gt;Cython&lt;/a&gt;, I often get the question how it compares to other tools like &lt;a class="reference external" href="https://pybind11.readthedocs.io/"&gt;pybind11&lt;/a&gt; and &lt;a class="reference external" href="https://cffi.readthedocs.io/"&gt;cffi&lt;/a&gt;.
There are others, but these are definitely the three that are widely used and "modern" in the sense that they provide an efficient user experience for today's real-world problems.
And as with all tools from the same problem space, there are overlaps and differences.
First of all, pybind11 and cffi are pure wrapping tools, whereas Cython is a Python compiler and a complete programming language that is used to implement actual functionality and not just bind to it.
So let's focus on the area where the three tools compete: extending Python with native code and libraries.&lt;/p&gt;
&lt;p&gt;Using native code from the Python runtime (specifically CPython) has been at the heart of the Python ecosystem since the very early days.
Python is a great language for all sorts of programming needs, but it would not have the success and would not be where it is today without its great ecosystem that is heavily based on fast, low-level, native code.
And the world of computing is full of such code, often decades old, heavily tuned, well tested and production proven.
Looking at indicators like the &lt;a class="reference external" href="https://www.tiobe.com/tiobe-index/"&gt;TIOBE Index&lt;/a&gt; suggests that low-level languages like C and C++ are becoming more and more important again even in the last years, decades after their creation.&lt;/p&gt;
&lt;p&gt;Today, no-one would attempt to design a (serious/practical) programming language anymore that does not come out of the box with a complete and easy to use way to access all that native code.
This ability is often referred to as an &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Foreign_function_interface"&gt;FFI&lt;/a&gt;, a foreign function interface.
&lt;a class="reference external" href="https://www.rust-lang.org/"&gt;Rust&lt;/a&gt; is an excellent example for a modern language that was designed with that ability in mind.
The FFI in &lt;a class="reference external" href="https://luajit.org/"&gt;LuaJIT&lt;/a&gt; is a great design of a fast and easy to use FFI for the &lt;a class="reference external" href="https://www.lua.org/"&gt;Lua language&lt;/a&gt;.
Even Java and its JVM, which are certainly not known for their ease of code reuse, have provided the JNI (Java Native Interface) from the early days.
CPython, being written in C, has made it very easy to interface with C code right from the start, and above all others the whole scientific computing and big data community has made great use of that over the past 25 years.&lt;/p&gt;
&lt;p&gt;Over time, many tools have aimed to simplify the wrapping of external code.
The venerable &lt;a class="reference external" href="http://swig.org/"&gt;SWIG&lt;/a&gt; with its long list of supported target languages is clearly worth mentioning here.
Partially a successor to SWIG (and &lt;a class="reference external" href="https://riverbankcomputing.com/software/sip/intro"&gt;sip&lt;/a&gt;), &lt;a class="reference external" href="https://pyside.github.io/docs/shiboken/"&gt;shiboken&lt;/a&gt; is a C++ bindings generator used by the &lt;a class="reference external" href="https://pyside.github.io/"&gt;PySide&lt;/a&gt; project to auto-create wrapper code for the large Qt C++ API.&lt;/p&gt;
&lt;p&gt;A general shortcoming of all wrapper generators is that many users eventually reach the limits of their capabilities, be it in terms of performance, feature support, language integration to one side or the other, or whatever.
From that point on, users start fighting the tool in order to make it support their use case at hand, and it is not unheard of that projects start over from scratch with a different tool.
Therefore, most projects are better off starting directly with a manually written wrapper, at least when the part of the native API that they need to wrap is not prohibitively vast.&lt;/p&gt;
&lt;p&gt;The &lt;a class="reference external" href="https://lxml.de/"&gt;lxml&lt;/a&gt; XML toolkit is an excellent example for that.
It wraps &lt;a class="reference external" href="http://xmlsoft.org/html/index.html"&gt;libxml2&lt;/a&gt; and &lt;a class="reference external" href="http://xmlsoft.org/XSLT/html/libxslt-lib.html"&gt;libxslt&lt;/a&gt; with their huge low-level C-APIs.
But if the project had used a wrapper generator to wrap it for Python, mapping this C-API to Python would have made the language integration of the Python-level API close to unusable.
In fact, the whole project &lt;a class="reference external" href="https://lxml.de/intro.html"&gt;started&lt;/a&gt; because generated Python bindings for both already existed that were &lt;a class="reference external" href="https://web.archive.org/web/20110902041836/http://diveintomark.org/archives/2004/02/18/libxml2"&gt;like the thrilling embrace of an exotic stranger&lt;/a&gt; (Mark Pilgrim).
And beautifying the API at the Python level by adding another Python wrapper layer would have countered the advantages of a generated wrapper and also severely limited its performance.
Despite the sheer vastness of the C-API that it wraps, the decision for manual wrapping and against a wrapper generator was the foundation of a very fast and highly pythonic tool.&lt;/p&gt;
&lt;p&gt;Nowadays, three modern tools are widely used in the Python community that support manual wrapping: Cython, cffi and pybind11.
These three tools serve three different sides of the need to extend (C)Python with native code.&lt;/p&gt;
&lt;p class="graphviz"&gt;&lt;img src="http://blog.behnel.de/assets/graphviz/0f4422f73ca846e50a60b71a45a6b819.svg" alt=""&gt;&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cython&lt;/strong&gt; is Python with native C/C++ data types.&lt;/p&gt;
&lt;p&gt;Cython is a static Python compiler.
For people coming from a Python background, it is much easier to express their coding needs in Python and then optimising and tuning them, than to rewrite them in a foreign language.
Cython allows them to do that by automatically translating their Python code to C, which often avoids the need for an implementation in a low-level language.&lt;/p&gt;
&lt;p&gt;Cython uses C type declarations to mix C/C++ operations into Python code freely, be it the usage of C/C++ data types and containers, or of C/C++ functions and objects defined in external libraries.
There is a very concise Cython syntax that uses special additional keywords (&lt;code class="docutils literal"&gt;cdef&lt;/code&gt;) outside of Python syntax, as well as &lt;a class="reference external" href="http://docs.cython.org/en/latest/src/tutorial/pure.html"&gt;ways to declare C types in pure Python syntax&lt;/a&gt;.
The latter allows writing type annotated Python code that gets optimised into fast C level when compiled by Cython, but that remains entirely pure Python code that can be run, analysed ad debugged with the usual Python tools.&lt;/p&gt;
&lt;p&gt;When it comes to wrapping native libraries, Cython has strong support for &lt;em&gt;designing&lt;/em&gt; a Python API for them.
Being Python, it really keeps the developer focussed on the usage from the Python side and on solving the problem at hand, and takes care of most of the boilerplate code through automatic type conversions and low-level code generation.
Its usage is essentially writing C code without having to write C code, but remaining in the wonderful world of the Python language.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;pybind11&lt;/strong&gt; is modern C++ with Python integration.&lt;/p&gt;
&lt;p&gt;pybind11 is the exact opposite of Cython.
Coming from C++, and targeting C++ developers, it provides a C++ API that wraps native functions and classes into Python representations.
For that, it makes good use of the compile time introspection features that were added to C++11 (hence the name).
Thus, it keeps the user focussed on the C++ side of things and takes care of the boilerplate code for mapping it to a Python API.&lt;/p&gt;
&lt;p&gt;For everyone who is comfortable with programming in C++ and wants to make direct use of all C++ features, pybind11 is the easiest way to make the C++ code available to Python.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CFFI&lt;/strong&gt; is Python with a dynamic runtime interface to native code.&lt;/p&gt;
&lt;p&gt;cffi then is the dynamic way to load and bind to external shared libraries from regular Python code.
It is similar to the &lt;a class="reference external" href="https://docs.python.org/library/ctypes.html"&gt;ctypes&lt;/a&gt; module in the Python standard library, but generally faster and easier to use.
Also, it has very good support for the PyPy Python runtime, still better than what Cython and pybind11 can offer.
However, the runtime overhead prevents it from coming any close in performance to the statically compiled code that Cython and pybind11 generate for CPython.
And the dependency on a well-defined ABI (binary interface) means that C++ support is mostly lacking.&lt;/p&gt;
&lt;p&gt;As long as there is a clear API-to-ABI mapping of a shared library, cffi can directly load and use the library file at runtime, given a header file description of the API.
In the more complex cases (e.g. when macros are involved), cffi uses a C compiler to generate a native stub wrapper from the description and uses that to communicate with the library.
That raises the runtime dependency bar quite a bit compared to ctypes (and both Cython and pybind11 only need a C compiler at build time, not at runtime), but on the other hand also enables wrapping library APIs that are difficult to use with ctypes.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This list shows the clear tradeoffs of the three tools.
If performance is not important, if dynamic runtime access to libraries is an advantage, and if users prefer writing their wrapping code in Python, then cffi (or even ctypes) will do the job, nicely and easily.
Otherwise, users with a strong C++ background will probably prefer pybind11 since it allows them to write functionality and wrapper code in C++ without switching between languages.
For users with a Python background (or at least not with a preference for C/C++), Cython will be very easy to learn and use since the code remains Python, but gains the ability to do efficient native C/C++ operations at any point.&lt;/p&gt;</description><category>Cython</category><category>english</category><category>Planet Python</category><category>Python</category><guid>http://blog.behnel.de/posts/cython-pybind11-cffi-which-tool-to-choose/</guid><pubDate>Fri, 14 Sep 2018 22:29:09 GMT</pubDate></item><item><title>What CPython could use Cython for</title><link>http://blog.behnel.de/posts/what-cpython-could-use-cython-for/</link><dc:creator>Stefan Behnel</dc:creator><description>&lt;p&gt;There has been a &lt;a class="reference external" href="https://mail.python.org/pipermail/python-dev/2018-August/154929.html"&gt;recent discussion&lt;/a&gt; about
using &lt;a class="reference external" href="http://cython.org/"&gt;Cython&lt;/a&gt; for CPython development.
I think this is a great opportunity for the CPython project to make more efficient use of its scarcest resource: developer time of its spare time contributors and maintainers.&lt;/p&gt;
&lt;p&gt;The entry level for new contributors to the CPython project is often perceived to be quite high.
While many tasks are actually beginner friendly, such as helping with the documentation or adding features to the Python modules in the stdlib,
such important tasks as fixing bugs in the core interpreter, working on data structures, optimising language constructs, or improving the test coverage of the C-API require a solid understanding of C and the CPython C-API.&lt;/p&gt;
&lt;p&gt;Since a large part of CPython is implemented in C, and since it exposes a large C-API to extensions and applications, &lt;strong&gt;C level testing&lt;/strong&gt; is key to providing a correct and reliable native API.
There were a couple of cases in the past years where new CPython releases actually broke certain parts of the C-API, and it was not noticed until people complained that their applications broke when trying out the new release.
This is because the test coverage of the C-API is much lower than the well tested Python level and standard library tests of the runtime.
And the main reason for this is that it is much more difficult to write tests in C than in Python, so people have a high incentive to get around it if they can.
Since the C-API is used internally inside of the runtime, it is often assumed to be implicitly tested by the Python tests anyway, which raises the bar for an explicit C test even further.
But this implicit coverage is not always given, and it also does not reduce the need for regression tests.
Cython could help here by making it easier to write C level tests that integrate nicely with the existing Python unit test framework that the CPython project uses.&lt;/p&gt;
&lt;p&gt;Basically, writing a C level test in Cython means writing a Python unittest function and then doing an explicit C operation in it that represents the actual test code.
Here is an example for testing the &lt;a class="reference external" href="https://docs.python.org/3/c-api/list.html#c.PyList_Append"&gt;PyList_Append&lt;/a&gt; C-API function:&lt;/p&gt;
&lt;pre class="code cython"&gt;&lt;a id="rest_code_226166bec7304fb79703691204c9f146-1" name="rest_code_226166bec7304fb79703691204c9f146-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;cpython.object&lt;/span&gt; &lt;span class="k"&gt;cimport&lt;/span&gt; &lt;span class="n"&gt;PyObject&lt;/span&gt;
&lt;a id="rest_code_226166bec7304fb79703691204c9f146-2" name="rest_code_226166bec7304fb79703691204c9f146-2"&gt;&lt;/a&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;cpython.list&lt;/span&gt; &lt;span class="k"&gt;cimport&lt;/span&gt; &lt;span class="n"&gt;PyList_Append&lt;/span&gt;
&lt;a id="rest_code_226166bec7304fb79703691204c9f146-3" name="rest_code_226166bec7304fb79703691204c9f146-3"&gt;&lt;/a&gt;
&lt;a id="rest_code_226166bec7304fb79703691204c9f146-4" name="rest_code_226166bec7304fb79703691204c9f146-4"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_PyList_Append_on_empty_list&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;a id="rest_code_226166bec7304fb79703691204c9f146-5" name="rest_code_226166bec7304fb79703691204c9f146-5"&gt;&lt;/a&gt;    &lt;span class="c"&gt;# setup code&lt;/span&gt;
&lt;a id="rest_code_226166bec7304fb79703691204c9f146-6" name="rest_code_226166bec7304fb79703691204c9f146-6"&gt;&lt;/a&gt;    &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;a id="rest_code_226166bec7304fb79703691204c9f146-7" name="rest_code_226166bec7304fb79703691204c9f146-7"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mf"&gt;0&lt;/span&gt;
&lt;a id="rest_code_226166bec7304fb79703691204c9f146-8" name="rest_code_226166bec7304fb79703691204c9f146-8"&gt;&lt;/a&gt;    &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"abc"&lt;/span&gt;
&lt;a id="rest_code_226166bec7304fb79703691204c9f146-9" name="rest_code_226166bec7304fb79703691204c9f146-9"&gt;&lt;/a&gt;    &lt;span class="n"&gt;pyobj_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;PyObject&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
&lt;a id="rest_code_226166bec7304fb79703691204c9f146-10" name="rest_code_226166bec7304fb79703691204c9f146-10"&gt;&lt;/a&gt;    &lt;span class="n"&gt;refcount_before&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pyobj_value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ob_refcnt&lt;/span&gt;
&lt;a id="rest_code_226166bec7304fb79703691204c9f146-11" name="rest_code_226166bec7304fb79703691204c9f146-11"&gt;&lt;/a&gt;
&lt;a id="rest_code_226166bec7304fb79703691204c9f146-12" name="rest_code_226166bec7304fb79703691204c9f146-12"&gt;&lt;/a&gt;    &lt;span class="c"&gt;# conservative test call, translates to the expected C code,&lt;/span&gt;
&lt;a id="rest_code_226166bec7304fb79703691204c9f146-13" name="rest_code_226166bec7304fb79703691204c9f146-13"&gt;&lt;/a&gt;    &lt;span class="c"&gt;# although with automatic exception propagation if it returns -1:&lt;/span&gt;
&lt;a id="rest_code_226166bec7304fb79703691204c9f146-14" name="rest_code_226166bec7304fb79703691204c9f146-14"&gt;&lt;/a&gt;    &lt;span class="n"&gt;errcode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PyList_Append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_226166bec7304fb79703691204c9f146-15" name="rest_code_226166bec7304fb79703691204c9f146-15"&gt;&lt;/a&gt;
&lt;a id="rest_code_226166bec7304fb79703691204c9f146-16" name="rest_code_226166bec7304fb79703691204c9f146-16"&gt;&lt;/a&gt;    &lt;span class="c"&gt;# validation&lt;/span&gt;
&lt;a id="rest_code_226166bec7304fb79703691204c9f146-17" name="rest_code_226166bec7304fb79703691204c9f146-17"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;errcode&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mf"&gt;0&lt;/span&gt;
&lt;a id="rest_code_226166bec7304fb79703691204c9f146-18" name="rest_code_226166bec7304fb79703691204c9f146-18"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mf"&gt;1&lt;/span&gt;
&lt;a id="rest_code_226166bec7304fb79703691204c9f146-19" name="rest_code_226166bec7304fb79703691204c9f146-19"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
&lt;a id="rest_code_226166bec7304fb79703691204c9f146-20" name="rest_code_226166bec7304fb79703691204c9f146-20"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;pyobj_value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ob_refcnt&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;refcount_before&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;p&gt;In the Cython project itself, what we actually do is to write &lt;a class="reference external" href="https://docs.python.org/3/library/doctest.html"&gt;doctests&lt;/a&gt;.
The functions and classes in a test module are compiled with Cython, and the doctests are then executed in Python, and call the Cython implementations.
This provides a very nice and easy way to compare the results of Cython operations with those of Python, and also trivially supports data driven tests, by calling a function multiple times from a doctest, for example:&lt;/p&gt;
&lt;pre class="code cython"&gt;&lt;a id="rest_code_8995e08d795d401199872c29039d9675-1" name="rest_code_8995e08d795d401199872c29039d9675-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;cpython.number&lt;/span&gt; &lt;span class="k"&gt;cimport&lt;/span&gt; &lt;span class="n"&gt;PyNumber_Add&lt;/span&gt;
&lt;a id="rest_code_8995e08d795d401199872c29039d9675-2" name="rest_code_8995e08d795d401199872c29039d9675-2"&gt;&lt;/a&gt;
&lt;a id="rest_code_8995e08d795d401199872c29039d9675-3" name="rest_code_8995e08d795d401199872c29039d9675-3"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_PyNumber_Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_8995e08d795d401199872c29039d9675-4" name="rest_code_8995e08d795d401199872c29039d9675-4"&gt;&lt;/a&gt;    &lt;span class="sd"&gt;"""&lt;/span&gt;
&lt;a id="rest_code_8995e08d795d401199872c29039d9675-5" name="rest_code_8995e08d795d401199872c29039d9675-5"&gt;&lt;/a&gt;&lt;span class="sd"&gt;    &amp;gt;&amp;gt;&amp;gt; test_PyNumber_Add('abc', 'def')&lt;/span&gt;
&lt;a id="rest_code_8995e08d795d401199872c29039d9675-6" name="rest_code_8995e08d795d401199872c29039d9675-6"&gt;&lt;/a&gt;&lt;span class="sd"&gt;    'abcdef'&lt;/span&gt;
&lt;a id="rest_code_8995e08d795d401199872c29039d9675-7" name="rest_code_8995e08d795d401199872c29039d9675-7"&gt;&lt;/a&gt;&lt;span class="sd"&gt;    &amp;gt;&amp;gt;&amp;gt; test_PyNumber_Add('abc', '')&lt;/span&gt;
&lt;a id="rest_code_8995e08d795d401199872c29039d9675-8" name="rest_code_8995e08d795d401199872c29039d9675-8"&gt;&lt;/a&gt;&lt;span class="sd"&gt;    'abc'&lt;/span&gt;
&lt;a id="rest_code_8995e08d795d401199872c29039d9675-9" name="rest_code_8995e08d795d401199872c29039d9675-9"&gt;&lt;/a&gt;&lt;span class="sd"&gt;    &amp;gt;&amp;gt;&amp;gt; test_PyNumber_Add(2, 5)&lt;/span&gt;
&lt;a id="rest_code_8995e08d795d401199872c29039d9675-10" name="rest_code_8995e08d795d401199872c29039d9675-10"&gt;&lt;/a&gt;&lt;span class="sd"&gt;    7&lt;/span&gt;
&lt;a id="rest_code_8995e08d795d401199872c29039d9675-11" name="rest_code_8995e08d795d401199872c29039d9675-11"&gt;&lt;/a&gt;&lt;span class="sd"&gt;    &amp;gt;&amp;gt;&amp;gt; -2 + 5&lt;/span&gt;
&lt;a id="rest_code_8995e08d795d401199872c29039d9675-12" name="rest_code_8995e08d795d401199872c29039d9675-12"&gt;&lt;/a&gt;&lt;span class="sd"&gt;    3&lt;/span&gt;
&lt;a id="rest_code_8995e08d795d401199872c29039d9675-13" name="rest_code_8995e08d795d401199872c29039d9675-13"&gt;&lt;/a&gt;&lt;span class="sd"&gt;    &amp;gt;&amp;gt;&amp;gt; test_PyNumber_Add(-2, 5)&lt;/span&gt;
&lt;a id="rest_code_8995e08d795d401199872c29039d9675-14" name="rest_code_8995e08d795d401199872c29039d9675-14"&gt;&lt;/a&gt;&lt;span class="sd"&gt;    3&lt;/span&gt;
&lt;a id="rest_code_8995e08d795d401199872c29039d9675-15" name="rest_code_8995e08d795d401199872c29039d9675-15"&gt;&lt;/a&gt;&lt;span class="sd"&gt;    """&lt;/span&gt;
&lt;a id="rest_code_8995e08d795d401199872c29039d9675-16" name="rest_code_8995e08d795d401199872c29039d9675-16"&gt;&lt;/a&gt;    &lt;span class="c"&gt;# The following is equivalent to writing "return a + b" in Python or Cython.&lt;/span&gt;
&lt;a id="rest_code_8995e08d795d401199872c29039d9675-17" name="rest_code_8995e08d795d401199872c29039d9675-17"&gt;&lt;/a&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;PyNumber_Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;p&gt;This could even trivially be combined with &lt;a class="reference external" href="https://pypi.org/project/hypothesis/"&gt;hypothesis&lt;/a&gt; and other data driven testing tools.&lt;/p&gt;
&lt;p&gt;But Cython's use cases are not limited to testing.
Maintenance and feature development would probably benefit even more from a reduced entry level.&lt;/p&gt;
&lt;p&gt;Many language optimisations are applied in the &lt;strong&gt;AST optimiser&lt;/strong&gt; these days, and that is implemented in C.
However, these tree operations can be fairly complex and are thus non-trivial to implement.
Doing that in Python rather than C would be much easier to write and maintain, but since this code is a part of the Python compilation process, there's a chicken-and-egg problem here in addition to the performance problem.
Cython could solve both problems and allow for more far-reaching optimisations by keeping the necessary transformation code readable.&lt;/p&gt;
&lt;p&gt;Performance is also an issue in other parts of CPython, namely the &lt;strong&gt;standard library&lt;/strong&gt;.
Several stdlib modules are compute intensive.
Many of them have two implementations: one in Python and a faster one in C, a so-called accelerator module.
This means that adding a feature to these modules requires duplicate effort, the proficiency in both Python and C, and a solid understanding of the C-API, reference counting, garbage collection, and what not.
On the other hand, many modules that could certainly benefit from native performance lack such an accelerator, e.g. &lt;code class="docutils literal"&gt;difflib&lt;/code&gt;, &lt;code class="docutils literal"&gt;textwrap&lt;/code&gt;, &lt;code class="docutils literal"&gt;fractions&lt;/code&gt;, &lt;code class="docutils literal"&gt;statistics&lt;/code&gt;, &lt;code class="docutils literal"&gt;argparse&lt;/code&gt;, &lt;code class="docutils literal"&gt;email&lt;/code&gt;, &lt;code class="docutils literal"&gt;urllib.parse&lt;/code&gt; and many, many more.
The &lt;code class="docutils literal"&gt;asyncio&lt;/code&gt; module is becoming more and more important these days, but its native accelerator only covers a very small part of its large functionality, and it also does not expose a native API that performance hungry async tools could hook into.
And even though the native accelerator of the &lt;code class="docutils literal"&gt;ElementTree&lt;/code&gt; module is an almost complete replacement, the somewhat complex serialisation code is still implemented completely in Python, which shows in comparison to the native serialisation in &lt;a class="reference external" href="https://lxml.de/"&gt;lxml&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Compiling these modules with Cython would speed them up, probably quite visibly.
For this use case, it is possible to keep the code entirely in Python, and just add enough &lt;a class="reference external" href="http://docs.cython.org/en/latest/src/tutorial/pure.html#static-typing"&gt;type declarations&lt;/a&gt; to make it fast when compiled.
The typing syntax that PEP-484 and PEP-526 added to Python 3.6 makes this really easy and straight forward.
A manually written accelerator module could thus be avoided, and therefore a lot of duplicated functionality and maintenance overhead.&lt;/p&gt;
&lt;p&gt;Feature development would also be substantially simplified, especially for new contributors.
Since Cython compiles Python code, it would allow people to contribute a &lt;strong&gt;Python implementation of a new feature&lt;/strong&gt; that compiles down to C.
And we all know that developing new functionality is much easier in Python than in C.
The remaining task is then only to optimise it and not to rewrite it in a different language.&lt;/p&gt;
&lt;p&gt;My feeling is that replacing some parts of the CPython C development with Cython has the potential to bring a visible boost for the contributions to the CPython project.&lt;/p&gt;
&lt;p&gt;Update 2018-09-12:
Jeroen Demeyer reminded me that I should also mention the ease of &lt;strong&gt;wrapping external native libraries&lt;/strong&gt;.
While this is not something that is a big priority for the standard library anymore, it is certainly true that modules like &lt;code class="docutils literal"&gt;sqlite&lt;/code&gt; (which wraps &lt;code class="docutils literal"&gt;sqlite3&lt;/code&gt;), &lt;code class="docutils literal"&gt;ssl&lt;/code&gt; (&lt;code class="docutils literal"&gt;OpenSSL&lt;/code&gt;), &lt;code class="docutils literal"&gt;expat&lt;/code&gt; or even the &lt;code class="docutils literal"&gt;io&lt;/code&gt; module (which wraps system I/O capabilities) would have been easier to write and maintain in Cython than in C.  Especially I/O related code is often intensive in error handling, which is nicer to do with &lt;code class="docutils literal"&gt;raise&lt;/code&gt; and f-strings than error code passing in C.&lt;/p&gt;</description><category>Cython</category><category>english</category><category>Planet Python</category><category>Python</category><guid>http://blog.behnel.de/posts/what-cpython-could-use-cython-for/</guid><pubDate>Sun, 09 Sep 2018 20:42:14 GMT</pubDate></item><item><title>A really fast Python web server with Cython</title><link>http://blog.behnel.de/posts/fast-python-web-server-with-cython/</link><dc:creator>Stefan Behnel</dc:creator><description>&lt;p&gt;Shortly after I wrote about &lt;a class="reference external" href="http://blog.behnel.de/posts/fast-python-web-server-with-cython/cython-for-web-frameworks.html"&gt;speeding up Python web frameworks with Cython&lt;/a&gt;,
&lt;a class="reference external" href="https://www.nexedi.com/"&gt;Nexedi&lt;/a&gt; posted an article about their attempt to build
&lt;a class="reference external" href="https://www.nexedi.com/NXD-Blog.Multicore.Python.HTTP.Server"&gt;a fast multicore web server for Python&lt;/a&gt;
that can compete with the performance of compiled coroutines in the Go language.&lt;/p&gt;
&lt;p&gt;Their goal is to use Cython to build a web framework around a fast native web server, and to use Cython's concurrency and coroutine support to gain native performance also in the application code, without sacrificing the readability that Python provides.&lt;/p&gt;
&lt;p&gt;Their experiments look very promising so far.
They managed to process 10K requests per second concurrently, which actually do real processing work.
That is worth noting, because many web server benchmarks out there content themselves with the blank response time for a "hello world", thus ignoring any concurrency overhead etc.
For that simple static "Hello world!", they even got 400K requests per second, which shows that this is not a very realistic benchmark.
Under load, their system seems to scale pretty linearly with the number of threads, also not a given among web frameworks.&lt;/p&gt;
&lt;p&gt;I might personally get involved in further improving Cython for this kind of concurrent, async applications.  Stay tuned.&lt;/p&gt;</description><category>Cython</category><category>english</category><category>Planet Python</category><category>Python</category><guid>http://blog.behnel.de/posts/fast-python-web-server-with-cython/</guid><pubDate>Sun, 15 Jul 2018 19:42:51 GMT</pubDate></item><item><title>Cython for web frameworks</title><link>http://blog.behnel.de/posts/cython-for-web-frameworks/</link><dc:creator>Stefan Behnel</dc:creator><description>&lt;p&gt;I'm excited to see the Python web community pick up &lt;a class="reference external" href="http://cython.org"&gt;Cython&lt;/a&gt; more and more to speed up their web frameworks.&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="https://github.com/MagicStack/uvloop/"&gt;uvloop&lt;/a&gt; as a fast drop-in replacement for asyncio has been around for a while now, and it's mostly written in Cython as a wrapper around &lt;a class="reference external" href="https://github.com/libuv/libuv"&gt;libuv&lt;/a&gt;.
The &lt;a class="reference external" href="http://falconframework.org/"&gt;Falcon web framework&lt;/a&gt; optionally compiles itself with Cython, while keeping up support for PyPy as a plain Python package.
New projects like &lt;a class="reference external" href="https://github.com/vibora-io/vibora"&gt;Vibora&lt;/a&gt; show that it pays off to design a framework for both (Flask-like) simplicity and (native) speed from the ground up to leverage Cython for the critical parts.
Quote of the day:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;"300.000 req/sec is a number comparable to Go's built-in web server (I'm saying this based on a rough test I made some years ago). Given that Go is designed to do exactly that, this is really impressive. My kudos to your choice to use Cython."
– &lt;a class="reference external" href="https://www.reddit.com/r/Python/comments/8scbgm/fast_asynchronous_and_sexy_python_web_framework/e0z706z/"&gt;Reddit user 'beertown'&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Alex Orlov gave a talk at the PyCon-US in 2017 about &lt;a class="reference external" href="https://pyvideo.org/pycon-us-2017/cython-as-a-game-changer-for-efficiency.html"&gt;using Cython for more efficient code&lt;/a&gt;,
in which he mentioned the possibility to speed up the Django URL dispatcher by 3x, simply by compiling the module as it is.&lt;/p&gt;
&lt;p&gt;Especially in async frameworks, minimising the time spent in processing (i.e. outside of the I/O-Loop) is critical for the overall responsiveness and performance.
Anton Caceres and I presented &lt;a class="reference external" href="https://pyvideo.org/europython-2016/fast-async-code-with-cython-and-asyncio.html"&gt;fast async code with Cython&lt;/a&gt; at EuroPython 2016,
showing how to speed up async coroutines by compiling and optimising them.&lt;/p&gt;
&lt;p&gt;In order to minimise the processing time on the server, many template engines use native accelerators in one way or another, and writing those in Cython (instead of C/C++) is a huge boost in terms of maintenance (and probably also speed).
But several engines also generate Python code from a templating language, and those templates tend to be way more static than not (they are rarely runtime generated themselves).
Therefore, compiling the generated template code, or even better, directly targeting Cython with the code generation instead of just plain Python has the potential to speed up the template processing a lot.
For example, Cython has very fast support for &lt;a class="reference external" href="https://www.python.org/dev/peps/pep-0498/"&gt;PEP-498 f-strings&lt;/a&gt; and even transforms some '%'-formatting patterns into them to speed them up (also in code that requires backwards compatibility with older Python versions).
That can easily make a difference, but also the faster function and method calls or looping code that it generates.&lt;/p&gt;
&lt;p&gt;I'm sure there's way more to come and I'm happily looking forward to all those cool developments in the web area that we are only just starting to see appear.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update 2018-07-15&lt;/strong&gt;: Nexedi posted an &lt;a class="reference external" href="http://blog.behnel.de/posts/cython-for-web-frameworks/fast-python-web-server-with-cython.html"&gt;article&lt;/a&gt; about their attempts to build a fast web server using Cython, both for the framework layer and the processing at the application layer.
Worth keeping an eye on.&lt;/p&gt;</description><category>Cython</category><category>english</category><category>Planet Python</category><category>Python</category><guid>http://blog.behnel.de/posts/cython-for-web-frameworks/</guid><pubDate>Sun, 24 Jun 2018 10:04:21 GMT</pubDate></item><item><title>What's new in Cython 0.28?</title><link>http://blog.behnel.de/posts/whats-new-in-cython-028/</link><dc:creator>Stefan Behnel</dc:creator><description>&lt;p&gt;The freshly released &lt;a class="reference external" href="http://cython.org"&gt;Cython 0.28&lt;/a&gt; is another major step in the development of the Cython compiler.
It comes with &lt;strong&gt;several big new features&lt;/strong&gt;, some of them long awaited, as well as various little optimisations.
It also improves the integration with recent Python features (including the upcoming Python 3.7) and the &lt;a class="reference external" href="https://pythran.readthedocs.io/"&gt;Pythran&lt;/a&gt; compiler for NumPy expressions.
The &lt;a class="reference external" href="https://github.com/cython/cython/blob/0.28/CHANGES.rst"&gt;Changelog&lt;/a&gt; has the long list of relevant changes.
As always, recompiling with the latest version will make your code adapt automatically to new Python releases and take advantage of the new optimisations.&lt;/p&gt;
&lt;p&gt;The most long requested change in this release, however, is the support for &lt;strong&gt;read-only memory views&lt;/strong&gt;.
You can now simply declare a memory view as &lt;code class="docutils literal"&gt;const&lt;/code&gt;, e.g. &lt;code class="docutils literal"&gt;const &lt;span class="pre"&gt;double[:,:]&lt;/span&gt;&lt;/code&gt;, and Cython will request a read-only buffer for it.
This allows interaction with bytes objects and other non-writable buffer providers.
Note that this makes the &lt;em&gt;item type&lt;/em&gt; of the memory view &lt;code class="docutils literal"&gt;const&lt;/code&gt;, i.e. non-writable, and not just the view itself.
If the item type is not just a simple numeric type, this might require minor changes to the data types used in the code reading from the view.
This feature was an open issue essentially ever since memory views were first introduced into Cython, back in 2009, but during all that time, no-one stepped forward to implement it.
Alongside with this improvement, users can now write &lt;code class="docutils literal"&gt;&lt;span class="pre"&gt;view[i][j]&lt;/span&gt;&lt;/code&gt; instead of &lt;code class="docutils literal"&gt;view[i,j]&lt;/code&gt; if they want to, without the previous slow-down due to sub-view creation.&lt;/p&gt;
&lt;p&gt;The second very long requested feature is the support for &lt;strong&gt;copying C code verbatimly&lt;/strong&gt; into the generated files.
The background is that some constructs, especially C hacks and macros, but also some adaptations to C specifics used by external libraries, can really only be done in plain C in order to use them from Cython.
Previously, users had to create an external C header file to implement these things and then use a &lt;code class="docutils literal"&gt;cdef extern from ...&lt;/code&gt; block to include the file from Cython code.
Cython 0.28 now allows docstrings on these &lt;code class="docutils literal"&gt;cdef extern&lt;/code&gt; blocks (with or without a specific header file name) that can contain arbitrary C/C++ code, for example:&lt;/p&gt;
&lt;pre class="code cython"&gt;&lt;a id="rest_code_eb320b1782ca4721a3f55144ab16625c-1" name="rest_code_eb320b1782ca4721a3f55144ab16625c-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;cdef&lt;/span&gt; &lt;span class="kr"&gt;extern&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_eb320b1782ca4721a3f55144ab16625c-2" name="rest_code_eb320b1782ca4721a3f55144ab16625c-2"&gt;&lt;/a&gt;    &lt;span class="sd"&gt;"""&lt;/span&gt;
&lt;a id="rest_code_eb320b1782ca4721a3f55144ab16625c-3" name="rest_code_eb320b1782ca4721a3f55144ab16625c-3"&gt;&lt;/a&gt;&lt;span class="sd"&gt;    #define add1(i) ((i) + 1)&lt;/span&gt;
&lt;a id="rest_code_eb320b1782ca4721a3f55144ab16625c-4" name="rest_code_eb320b1782ca4721a3f55144ab16625c-4"&gt;&lt;/a&gt;&lt;span class="sd"&gt;    """&lt;/span&gt;
&lt;a id="rest_code_eb320b1782ca4721a3f55144ab16625c-5" name="rest_code_eb320b1782ca4721a3f55144ab16625c-5"&gt;&lt;/a&gt;    &lt;span class="k"&gt;cdef&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;add1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;nogil&lt;/span&gt;
&lt;a id="rest_code_eb320b1782ca4721a3f55144ab16625c-6" name="rest_code_eb320b1782ca4721a3f55144ab16625c-6"&gt;&lt;/a&gt;
&lt;a id="rest_code_eb320b1782ca4721a3f55144ab16625c-7" name="rest_code_eb320b1782ca4721a3f55144ab16625c-7"&gt;&lt;/a&gt;&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;add1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;p&gt;This is definitely considered an expert feature.
Since the code is copied verbatimly into the generated C code file, Cython has no way to apply any validation or safety checks.
Use at your own risk.&lt;/p&gt;
&lt;p&gt;Another big new feature is the support for &lt;strong&gt;multiple inheritance from Python classes by extension types&lt;/strong&gt; (a.k.a. cdef classes).
Previously, extension types could only inherit from other natively implemented types, inlcuding builtins.
While cdef classes still cannot inherit &lt;em&gt;only&lt;/em&gt; from Python classes, and also cannot inherit from multiple &lt;em&gt;cdef&lt;/em&gt; classes,
it is now possible to use normal Python classes as &lt;em&gt;additional&lt;/em&gt; base classes, following an extension type as primary base.
This enables use cases like Python mixins, while still keeping up the efficient memory layout and the fast C-level access to attributes and cdef methods that cdef classes provide.&lt;/p&gt;
&lt;p&gt;A bit of work has been done to start &lt;strong&gt;reducing the shared library size&lt;/strong&gt; of Cython generated extension modules.
In general, Cython aims to optimise its operations (especially Python operations) for speed and extensively uses C function inlining, optimistic code branches and type specialisations for that.
However, the code in the module init function is really only executed once and rarely contains any loops, certainly not time critical ones.
Therefore, Cython has now started to avoid certain code intensive optimisations inside of the module init code and also uses GCC pragmas to make the C compiler optimise this specific function for smaller size instead of speed.
Without making the import visibly slower, this results in a certain reduction of the overall library size, but probably still leaves some space for future improvements.&lt;/p&gt;
&lt;p&gt;Several &lt;strong&gt;new optimisations&lt;/strong&gt; for Python builtins were implemented and often contributed by users.
This includes faster operations and iteration for sets and bytearrays, from which existing code can benefit through simple recompilation.
We are always happy to receive these contributions, and several tickets in the bug tracker are now marked as beginner friendly "first issues".&lt;/p&gt;
&lt;p&gt;Cython has long supported &lt;strong&gt;f-strings&lt;/strong&gt;, and the new release brings another set of little &lt;strong&gt;performance improvements&lt;/strong&gt; for them.
More interestingly, however, several common cases of &lt;strong&gt;unicode string %-formatting are now mapped to the f-string builder&lt;/strong&gt;, as long as the argument side is a literal tuple.
If the template string uses no unsupported formats, Cython applies this transformation automatically, which leads to visibly faster string formatting and avoids the intermediate creation of Python number objects and the value tuple.
Existing code that makes use of %-formatting, including code in compiled Python &lt;code class="docutils literal"&gt;.py&lt;/code&gt; files that needs to stay compatible with Python 2.x, can therefore benefit directly without rewriting all the template strings.
Further coverage of formatting features for this transformation is certainly possible, and contributions are welcome.&lt;/p&gt;
&lt;p&gt;Finally, a last minute change improves the &lt;strong&gt;handling of string literals that are being passed into C++ functions&lt;/strong&gt; as &lt;code class="docutils literal"&gt;&lt;span class="pre"&gt;std::string&amp;amp;&lt;/span&gt;&lt;/code&gt; references.
Previously, the generated code always unpacked a Python byte string and made a fresh copy of it, whereas now Cython detects &lt;code class="docutils literal"&gt;const&lt;/code&gt; arguments and passes the string literal directly.
Also in the non-const case, Cython does not follow C++ in outright rejecting the literal argument at compile time, but instead just creates a writable copy and passes it into the function.
This avoids special casing in user code and leads to working code by default, as expected in Python, and Cython.&lt;/p&gt;</description><category>Cython</category><category>english</category><category>Planet Python</category><category>Python</category><guid>http://blog.behnel.de/posts/whats-new-in-cython-028/</guid><pubDate>Tue, 13 Mar 2018 22:05:16 GMT</pubDate></item></channel></rss>