Differences between Cython and Pyrex¶
Warning
Both Cython and Pyrex are moving targets. It has come to the pointthat an explicit list of all the differences between the twoprojects would be laborious to list and track, but hopefullythis high-level list gives an idea of the differences thatare present. It should be noted that both projects make an effortat mutual compatibility, but Cython’s goal is to be as close toand complete as Python as reasonable.
Python 3 Support¶
Cython creates.c
files that can be built and used with bothPython 2.x and Python 3.x. In fact, compiling your module withCython may very well be an easy way to port code to Python 3.
Cython also supports various syntax additions that came withPython 3.0 and later major Python releases. If they do not conflictwith existing Python 2.x syntax or semantics, they are usually justaccepted by the compiler. Everything else depends on thecompiler directivelanguage_level=3
(seecompiler directives).
List/Set/Dict Comprehensions¶
Cython supports the different comprehensions defined by Python 3 forlists, sets and dicts:
[expr(x)forxinA]# list{expr(x)forxinA}# set{key(x):value(x)forxinA}# dict
Looping is optimized ifA
is a list, tuple or dict. You can usethefor
…from
syntax, too, but it isgenerally preferred to use the usualfor
…in
range(...)
syntax with a C run variable (e.g.cdefinti
).
Note
Note that Cython also supports set literals starting from Python 2.4.
Keyword-only arguments¶
Python functions can have keyword-only arguments listed after the*
parameter and before the**
parameter if any, e.g.:
deff(a,b,*args,c,d=42,e,**kwds):...
Herec
,d
ande
cannot be passed as position arguments and must bepassed as keyword arguments. Furthermore,c
ande
are required keywordarguments, since they do not have a default value.
If the parameter name after the*
is omitted, the function will not accept anyextra positional arguments, e.g.:
defg(a,b,*,c,d):...
takes exactly two positional parameters and has two required keyword parameters.
Conditional expressions “x if b else y”¶
Conditional expressions as described inhttps://www.python.org/dev/peps/pep-0308/:
XifCelseY
Only one ofX
andY
is evaluated (depending on the value of C).
cdef inline¶
Module level functions can now be declared inline, with theinline
keyword passed on to the C compiler. These can be as fast as macros.:
cdefinlineintsomething_fast(inta,intb):returna*a+b
Note that class-levelcdef
functions are handled via a virtualfunction table, so the compiler won’t be able to inline them in almost allcases.
Assignment on declaration (e.g. “cdef int spam = 5”)¶
In Pyrex, one must write:
cdefinti,j,ki=2j=5k=7
Now, with cython, one can write:
cdefinti=2,j=5,k=7
The expression on the right hand side can be arbitrarily complicated, e.g.:
cdefintn=python_call(foo(x,y),a+b+c)-32
‘by’ expression in for loop (e.g. “for i from 0 <= i < 10 by 2”)¶
forifrom0<=i<10by2:printi
yields:
02468
Note
Usage of this syntax is discouraged as it is redundant with thenormal Pythonfor
loop.SeeAutomatic range conversion.
Boolean int type (e.g. it acts like a c int, but coerces to/from python as a boolean)¶
In C, ints are used for truth values. In python, any object can be used as atruth value (using the__nonzero__()
method), but the canonical choicesare the two boolean objectsTrue
andFalse
. Thebint
(for“boolean int”) type is compiled to a C int, but coerces to and fromPython as booleans. The return type of comparisons and several builtins is abint
as well. This reduces the need for wrapping things inbool()
. For example, one can write:
defis_equal(x):returnx==y
which would return1
or0
in Pyrex, but returnsTrue
orFalse
inCython. One can declare variables and return values for functions to be of thebint
type. For example:
cdefinti=xcdefbintb=x
The first conversion would happen viax.__int__()
whereas the second wouldhappen viax.__bool__()
(a.k.a.__nonzero__()
), with appropriateoptimisations for known builtin types.
Executable class bodies¶
Including a workingclassmethod()
:
cdefclassBlah:defsome_method(self):printselfsome_method=classmethod(some_method)a=2*3print"hi",a
cpdef functions¶
Cython adds a third function type on top of the usualdef
andcdef
. If a function is declaredcpdef
it can be calledfrom and overridden by both extension and normal python subclasses. You canessentially think of acpdef
method as acdef
method +some extras. (That’s how it’s implemented at least.) First, it creates adef
method that does nothing but call the underlyingcdef
method (and does argument unpacking/coercion if needed). Atthe top of thecdef
method a little bit of code is added to seeif it’s overridden, similar to the following pseudocode:
ifhasattr(type(self),'__dict__'):foo=self.fooiffooisnotwrapper_foo:returnfoo(args)[cdefmethodbody]
To detect whether or not a type has a dictionary, it just checks thetp_dictoffset
slot, which isNULL
(by default) for extension types,but non- null for instance classes. If the dictionary exists, it does a singleattribute lookup and can tell (by comparing pointers) whether or not thereturned result is actually a new function. If, and only if, it is a newfunction, then the arguments packed into a tuple and the method called. Thisis all very fast. A flag is set so this lookup does not occur if one calls themethod on the class directly, e.g.:
cdefclassA:cpdeffoo(self):passx=A()x.foo()# will check to see if overriddenA.foo(x)# will call A's implementation whether overridden or not
SeeEarly Binding for Speed for explanation and usage tips.
Automatic range conversion¶
This will convert statements of the formforiinrange(...)
toforifrom...
wheni
is any cdef’d integer type, and the direction (i.e. signof step) can be determined.
Warning
This may change the semantics if the range causesassignment toi
to overflow. Specifically, if this option is set, an errorwill be raised before the loop is entered, whereas without this option the loopwill execute until a overflowing value is encountered. If this affects you,changeCython/Compiler/Options.py
(eventually there will be a betterway to set this).
More friendly type casting¶
In Pyrex, if one types<int>x
wherex
is a Python object, one will getthe memory address ofx
. Likewise, if one types<object>i
wherei
is a C int, one will get an “object” at locationi
in memory. This leadsto confusing results and segfaults.
In Cython<type>x
will try and do a coercion (as would happen on assignment ofx
to a variable of type type) if exactly one of the types is a python object.It does not stop one from casting where there is no conversion (though it willemit a warning). If one really wants the address, cast to avoid*
first.
As in Pyrex<MyExtensionType>x
will castx
to typeMyExtensionType
without any type checking. Cython supports the syntax<MyExtensionType?>
to dothe cast with type checking (i.e. it will throw an error ifx
is not a(subclass of)MyExtensionType
.
Optional arguments in cdef/cpdef functions¶
Cython now supports optional arguments forcdef
andcpdef
functions.
The syntax in the.pyx
file remains as in Python, but one declares suchfunctions in the.pxd
file by writingcdeffoo(x=*)
. The number ofarguments may increase on subclassing, but the argument types and order mustremain the same. There is a slight performance penalty in some cases when acdef/cpdef function without any optional is overridden with one that does havedefault argument values.
For example, one can have the.pxd
file:
cdefclassA:cdeffoo(self)cdefclassB(A):cdeffoo(self,x=*)cdefclassC(B):cpdeffoo(self,x=*,intk=*)
with corresponding.pyx
file:
cdefclassA:cdeffoo(self):print("A")cdefclassB(A):cdeffoo(self,x=None):print("B",x)cdefclassC(B):cpdeffoo(self,x=True,intk=3):print("C",x,k)
Function pointers in structs¶
Functions declared instruct
are automatically converted tofunction pointers for convenience.
C++ Exception handling¶
cdef
functions can now be declared as:
cdefintfoo(...)except+cdefintfoo(...)except+TypeErrorcdefintfoo(...)except+python_error_raising_function
in which case a Python exception will be raised when a C++ error is caught.SeeUsing C++ in Cython for more details.
Synonyms¶
cdefimportfrom
means the same thing ascdefexternfrom
Source code encoding¶
Cython supportsPEP 3120 andPEP 263, i.e. you can start your Cython sourcefile with an encoding comment and generally write your source code in UTF-8.This impacts the encoding of byte strings and the conversion of unicode stringliterals likeu'abcd'
to unicode objects.
Automatictypecheck
¶
Rather than introducing a new keywordtypecheck
as explained in thePyrex docs,Cython emits a (non-spoofable and faster) typecheck wheneverisinstance()
is used with an extension type as the second parameter.
From __future__ directives¶
Cython supports severalfrom__future__import...
directives, namelyabsolute_import
,unicode_literals
,print_function
anddivision
.
With statements are always enabled.
Pure Python mode¶
Cython has support for compiling.py
files, andaccepting type annotations using decorators and othervalid Python syntax. This allows the same source tobe interpreted as straight Python, or compiled foroptimized results. SeePure Python Mode for more details.