Source Files and Compilation¶
Cython source file names consist of the name of the module followed by a.pyx
extension, for example a module called primes would have a sourcefile namedprimes.pyx
.
Cython code, unlike Python, must be compiled. This happens in two stages:
A
.pyx
(or.py
) file is compiled by Cython to a.c
file.The
.c
file is compiled by a C compiler to a.so
file (or a.pyd
file on Windows)
Once you have written your.pyx
/.py
file, there are a couple of wayshow to turn it into an extension module.
The following sub-sections describe several ways to build yourextension modules, and how to pass directives to the Cython compiler.
There are also a number of tools that process.pyx
files apart from Cython, e.g.
Compiling from the command line¶
There are two ways of compiling from the command line.
Thecython command takes a
.py
or.pyx
file andcompiles it into a C/C++ file.Thecythonize command takes a
.py
or.pyx
file andcompiles it into a C/C++ file. It then compiles the C/C++ file intoan extension module which is directly importable from Python.
Compiling with thecython command¶
One way is to compile it manually with the Cythoncompiler, e.g.:
$cythonprimes.pyx
This will produce a file calledprimes.c
, which then needs to becompiled with the C compiler using whatever options are appropriate on yourplatform for generating an extension module. For these options look at theofficial Python documentation.
The other, and probably better, way is to use thesetuptools
extensionprovided with Cython. The benefit of this method is that it will give theplatform specific compilation options, acting like a stripped down autotools.
Compiling with thecythonize command¶
Run thecythonize compiler command with your options and list of.pyx
files to generate an extension module. For example:
$cythonize-a-iyourmod.pyx
This creates ayourmod.c
file (oryourmod.cpp
in C++ mode), compiles it,and puts the resulting extension module (.so
or.pyd
, depending on yourplatform) next to the source file for direct import (-i
builds “in place”).The-a
switch additionally produces an annotated html file of the source code.
Thecythonize command accepts multiple source files and glob patterns like**/*.pyx
as argument and also understands the common-j
option forrunning multiple parallel build jobs. When called without further options, itwill only translate the source files to.c
or.cpp
files. Pass the-h
flag for a complete list of supported options.
There simpler command line toolcython only invokes the source code translator.
In the case of manual compilation, how to compile your.c
files will varydepending on your operating system and compiler. The Python documentation forwriting extension modules should have some details for your system. On a Linuxsystem, for example, it might look similar to this:
$gcc-shared-pthread-fPIC-fwrapv-O2-Wall-fno-strict-aliasing\-I/usr/include/python3.5-oyourmod.soyourmod.c
(gcc will need to have paths to your included header files and pathsto libraries you want to link with.)
After compilation, ayourmod.so
(yourmod.pyd
for Windows)file is written into the target directoryand your module,yourmod
, is available for you to import as with any otherPython module. Note that if you are not relying oncythonize orsetuptools
,you will not automatically benefit from the platform specific file extensionthat CPython generates for disambiguation, such asyourmod.cpython-35m-x86_64-linux-gnu.so
on a regular 64bit Linux installationof CPython 3.5.
Basicsetup.py
¶
The setuptools extension provided with Cython allows you to pass.pyx
filesdirectly to theExtension
constructor in your setup file.
If you have a single Cython file that you want to turn into a compiledextension, say with filenameexample.pyx
the associatedsetup.py
would be:
fromsetuptoolsimportsetupfromCython.Buildimportcythonizesetup(ext_modules=cythonize("example.pyx"))
If your build depends directly on Cython in this way,then you may also want to inform pip thatCython
is required forsetup.py
to execute, followingPEP 518,creating apyproject.toml
file containing, at least:
[build-system]requires=["setuptools","Cython"]
To understand thesetup.py
more fully look at the officialsetuptools documentation.To compile the extension for use in the current directory use:
$pythonsetup.pybuild_ext--inplace
Note
setuptools 74.1.0 adds experimental support for extensions inpyproject.toml
(instead ofsetup.py
):
[build-system]requires=["setuptools","cython"]build-backend="setuptools.build_meta"[project]name="mylib-foo"version="0.42"[tool.setuptools]ext-modules=[{name="example",sources=["example.pyx"]}]
In this case, you can use any build frontend - e.g.build
$python-mbuild
Configuring the C-Build¶
Note
More details on building Cython modules that use cimport numpy can be found in theNumpy section of the user guide.
If you haveCython include files orCython definition files in non-standard places you can pass aninclude_path
parameter tocythonize
:
fromsetuptoolsimportsetupfromCython.Buildimportcythonizesetup(name="My hello app",ext_modules=cythonize("src/*.pyx",include_path=[...]),)
If you need to specify compiler options, libraries to link with or otherlinker options you will need to createExtension
instances manually(note that glob syntax can still be used to specify multiple extensionsin one line):
fromsetuptoolsimportExtension,setupfromCython.Buildimportcythonizeextensions=[Extension("primes",["primes.pyx"],include_dirs=[...],libraries=[...],library_dirs=[...]),# Everything but primes.pyx is included here.Extension("*",["*.pyx"],include_dirs=[...],libraries=[...],library_dirs=[...]),]setup(name="My hello app",ext_modules=cythonize(extensions),)
Some useful options to know about are
include_dirs
- list of directories to search for C/C++ header files (in Unix form for portability),libraries
- list of library names (not filenames or paths) to link against,library_dirs
- list of directories to search for C/C++ libraries at link time.
Note that when using setuptools, you should import it before Cython, otherwise,both might disagree about the class to use here.
Often, Python packages that offer a C-level API provide a way to findthe necessary C header files:
fromsetuptoolsimportExtension,setupfromCython.Buildimportcythonizeextensions=[Extension("*",["*.pyx"],include_dirs=["/usr/local/include"]),]setup(name="My hello app",ext_modules=cythonize(extensions),)
If your options are static (for example you do not need to call a tool likepkg-config
to determine them) you can also provide them directly in your.pyx
or.pxd
source file using a special comment block at the start of the file:
# distutils: libraries = spam eggs# distutils: include_dirs = /opt/food/include
If you cimport multiple .pxd files defining libraries, then Cythonmerges the list of libraries, so this works as expected (similarlywith other options, likeinclude_dirs
above).
If you have some C files that have been wrapped with Cython and you want tocompile them into your extension, you can define the setuptoolssources
parameter:
# distutils: sources = [helper.c, another_helper.c]
Note that these sources are added to the list of sources of the currentextension module. Spelling this out in thesetup.py
file looksas follows:
fromsetuptoolsimportExtension,setupfromCython.Buildimportcythonizesourcefiles=['example.pyx','helper.c','another_helper.c']extensions=[Extension("example",sourcefiles)]setup(ext_modules=cythonize(extensions))
TheExtension
class takes many options, and a fuller explanation canbe found in thesetuptools documentation.
Sometimes this is not enough and you need finer customization of thesetuptoolsExtension
.To do this, you can provide a custom functioncreate_extension
to create the finalExtension
object after Cython has processedthe sources, dependencies and#distutils
directives but before thefile is actually Cythonized.This function takes 2 argumentstemplate
andkwds
, wheretemplate
is theExtension
object given as input to Cythonandkwds
is adict
with all keywords which should be usedto create theExtension
.The functioncreate_extension
must return a 2-tuple(extension,metadata)
, whereextension
is the createdExtension
andmetadata
is metadata which will be writtenas JSON at the top of the generated C files. This metadata is only usedfor debugging purposes, so you can put whatever you want in there(as long as it can be converted to JSON).The default function (defined inCython.Build.Dependencies
) is:
defdefault_create_extension(template,kwds):if'depends'inkwds:include_dirs=kwds.get('include_dirs',[])+["."]depends=resolve_depends(kwds['depends'],include_dirs)kwds['depends']=sorted(set(depends+template.depends))t=template.__class__ext=t(**kwds)ifhasattr(template,"py_limited_api"):ext.py_limited_api=template.py_limited_apimetadata=dict(distutils=kwds,module_name=kwds['name'])returnext,metadata
In case that you pass a string instead of anExtension
tocythonize()
, thetemplate
will be anExtension
withoutsources. For example, if you docythonize("*.pyx")
,thetemplate
will beExtension(name="*.pyx",sources=[])
.
Just as an example, this addsmylib
as library to every extension:
fromCython.Build.Dependenciesimportdefault_create_extensiondefmy_create_extension(template,kwds):libs=kwds.get('libraries',[])+["mylib"]kwds['libraries']=libsreturndefault_create_extension(template,kwds)ext_modules=cythonize(...,create_extension=my_create_extension)
Note
If you Cythonize in parallel (using thenthreads
argument),then the argument tocreate_extension
must be pickleable.In particular, it cannot be a lambda function.
Cythonize arguments¶
The functioncythonize()
can take extra arguments which will allow you tocustomize your build.
- Cython.Build.cythonize(module_list,exclude=None,nthreads=0,aliases=None,quiet=False,force=None,language=None,exclude_failures=False,show_all_warnings=False,**options)¶
Compile a set of source modules into C/C++ files and return a list of distutilsExtension objects for them.
- Parameters:
module_list – As module list, pass either a glob pattern, a list of globpatterns or a list of Extension objects. The latterallows you to configure the extensions separatelythrough the normal distutils options.You can also pass Extension objects that haveglob patterns as their sources. Then, cythonizewill resolve the pattern and create acopy of the Extension for every matching file.
exclude – When passing glob patterns as
module_list
, you can exclude certainmodule names explicitly by passing them into theexclude
option.nthreads – The number of concurrent builds for parallel compilation(requires the
multiprocessing
module).aliases – If you want to use compiler directives like
#distutils:...
butcan only know at compile time (when running thesetup.py
) which valuesto use, you can use aliases and pass a dictionary mapping those aliasesto Python strings when callingcythonize()
. As an example, say youwant to use the compilerdirective#distutils:include_dirs=../static_libs/include/
but this path isn’t always fixed and you want to find it when runningthesetup.py
. You can then do#distutils:include_dirs=MY_HEADERS
,find the value ofMY_HEADERS
in thesetup.py
, put it in a pythonvariable calledfoo
as a string, and then callcythonize(...,aliases={'MY_HEADERS':foo})
.quiet – If True, Cython won’t print error, warning, or status messages during thecompilation.
force – Forces the recompilation of the Cython modules, even if the timestampsdon’t indicate that a recompilation is necessary.
language – To globally enable C++ mode, you can pass
language='c++'
. Otherwise, thiswill be determined at a per-file level based on compiler directives. Thisaffects only modules found based on file names. Extension instances passedintocythonize()
will not be changed. It is recommended to ratheruse the compiler directive#distutils:language=c++
than this option.exclude_failures – For a broad ‘try to compile’ mode that ignores compilationfailures and simply excludes the failed extensions,pass
exclude_failures=True
. Note that this onlyreally makes sense for compiling.py
files which can alsobe used without compilation.show_all_warnings – By default, not all Cython warnings are printed.Set to true to show all warnings.
annotate – If
True
, will produce a HTML file for each of the.pyx
or.py
files compiled. The HTML file gives an indicationof how much Python interaction there is ineach of the source code lines, compared to plain C code.It also allows you to see the C/C++ codegenerated for each line of Cython code. This report is invaluable whenoptimizing a function for speed,and for determining when torelease the GIL:in general, anogil
block may contain only “white” code.See examples inDetermining where to add types orPrimes.annotate-fullc – If
True
will produce a colorized HTML version ofthe source which includes entire generated C/C++-code.compiler_directives – Allow to set compiler directives in the
setup.py
like this:compiler_directives={'embedsignature':True}
.SeeCompiler directives.depfile – produce depfiles for the sources if True.
cache – If
True
the cache enabled with default path. If the value is a path to a directory,then the directory is used to cache generated.c
/.cpp
files. By default cache is disabled.SeeCython cache.
Multiple Cython Files in a Package¶
To automatically compile multiple Cython files without listing all of themexplicitly, you can use glob patterns:
setup(ext_modules=cythonize("package/*.pyx"))
You can also use glob patterns inExtension
objects if you passthem throughcythonize()
:
extensions=[Extension("*",["*.pyx"])]setup(ext_modules=cythonize(extensions))
Distributing Cython modules¶
Following recent improvements in the distribution toolchain, it isnot recommended to include generated files in source distributions.Instead,require Cython at build-time to generate the C/C++ files,as defined inPEP 518 andPEP 621. SeeBasic setup.py.
It is, however, possible to distribute the generated.c
files together withyour Cython sources, so that users can install your module without needingto have Cython available.
Doing so allows you to make Cython compilation optional in theversion you distribute. Even if the user has Cython installed, they may notwant to use it just to install your module. Also, the installed versionmay not be the same one you used, and may not compile your sources correctly.
This simply means that thesetup.py
file that you ship with will justbe a normal setuptools file on the generated.c files, for the basic examplewe would have instead:
fromsetuptoolsimportExtension,setupsetup(ext_modules=[Extension("example",["example.c"])])
This is easy to combine withcythonize()
by changing the file extensionof the extension module sources:
fromsetuptoolsimportExtension,setupUSE_CYTHON=...# command line option, try-import, ...ext='.pyx'ifUSE_CYTHONelse'.c'extensions=[Extension("example",["example"+ext])]ifUSE_CYTHON:fromCython.Buildimportcythonizeextensions=cythonize(extensions)setup(ext_modules=extensions)
If you have many extensions and want to avoid the additional complexity in thedeclarations, you can declare them with their normal Cython sources and thencall the following function instead ofcythonize()
to adapt the sourceslist in theExtension
s when not using Cython:
importos.pathdefno_cythonize(extensions,**_ignore):forextensioninextensions:sources=[]forsfileinextension.sources:path,ext=os.path.splitext(sfile)ifextin('.pyx','.py'):ifextension.language=='c++':ext='.cpp'else:ext='.c'sfile=path+extsources.append(sfile)extension.sources[:]=sourcesreturnextensions
If you want to expose the C-level interface of your library for otherlibraries to cimport from, use package_data to install the.pxd
files,e.g.:
setup(package_data={'my_package':['*.pxd'],'my_package/sub_package':['*.pxd'],},...)
These.pxd
files need not have corresponding.pyx
modules if they contain purely declarations of external libraries.
Shared utility module¶
When a.pyx
/.py
file is compiled to.c
file, Cython automatically embedsinternal utility code into the resulting.c
file. For projects containing multipleCython modules, this can result in a larger total size of compiled extensions.To avoid redundant code, the common utility code can be extracted into a separate extensionmodule which is automatically cimported and used by the user-written extension modules.
Note
Currently, only memoryview utility code can be moved to the shared utility module.
Consider the following example package:
mypkg/+--__init__.py+--shared/|+--__init__.py|+--_cyutility.c+--subpkg1/+--__init__.py+--module.pyx
The_cyutility.c
file contains the shared utility code andmodule.pyx
isa standard Cython source file which will be compiled into an extension cimporting themypkg.shared._cyutility
module (automatically).The compilation process now consist of three steps:
Generating the shared utility code. This is done via the
--generate-shared
argument:$cython--generate-shared=mypkg/shared/_cyutility.c
Translating all
.pyx
files to.c
files with the--shared
argument to providethe fully qualified name of the shared module:$cython--shared=mypkg.shared._cyutilitymodule.pyx
Compiling the shared utility module and all other (user defined) extension modules.The shared utility module needs to be compiled as regular
.c
extension module,either by using the C compiler directly, or through setuptools, etc.
Warning
An extension module compiled with the--shared=...
argument automaticallyimports the shared module under the fully qualified name provided via theargument parameter. Failing to import the shared module will cause a failureto import the extension module that uses it.
Compiling shared module using setuptools¶
Ifsetuptools
is used in the build process, the fully qualified module nameof the shared utility module can be specified using theshared_utility_qualified_name
parameter ofcythonize()
(instead of the--shared
command line argument).To generate the extension sources of the shared module fromcythonize()
,you need to explicitly pass anExtension
object describing the module.Thesetup.py
file would be:
fromCython.BuildimportcythonizefromCython.CompilerimportOptionsfromsetuptoolsimportsetup,Extensionextensions=[Extension("*",["**/*.pyx"]),# Providing 'sources' is optional for the shared module.# If missing, the module package will be used for the path in 'build_dir'.Extension("mypkg.shared._cyutility",sources=["mypkg/shared/_cyutility.c"]),]setup(ext_modules=cythonize(extensions,shared_utility_qualified_name='mypkg.shared._cyutility'))
Integrating multiple modules¶
In some scenarios, it can be useful to link multiple Cython modules(or other extension modules) into a single binary, e.g. when embeddingPython in another application. This can be done through the inittabimport mechanism of CPython.
Create a new C file to integrate the extension modules and add thismacro to it:
#if PY_MAJOR_VERSION < 3# define MODINIT(name) init ## name#else# define MODINIT(name) PyInit_ ## name#endif
If you are only targeting Python 3.x, just usePyInit_
as prefix.
Then, for each of the modules, declare its module init functionas follows, replacingsome_module_name
with the name of the module:
PyMODINIT_FUNCMODINIT(some_module_name)(void);
In C++, declare them asexternC
.
If you are not sure of the name of the module init function, referto your generated module source file and look for a function namestarting withPyInit_
.
Next, before you start the Python runtime from your application codewithPy_Initialize()
, you need to initialise the modules at runtimeusing thePyImport_AppendInittab()
C-API function, again insertingthe name of each of the modules:
PyImport_AppendInittab("some_module_name",MODINIT(some_module_name));
This enables normal imports for the embedded extension modules.
In order to prevent the joined binary from exporting all of the moduleinit functions as public symbols, Cython 0.28 and later can hide thesesymbols if the macroCYTHON_NO_PYINIT_EXPORT
is defined whileC-compiling the module C files.
Also take a look at thecython_freeze tool.It can generate the necessary boilerplate code for linking one or moremodules into a single Python executable.
Compiling withpyximport
¶
For building Cython modules during development without explicitlyrunningsetup.py
after each change, you can usepyximport
:
>>>importpyximport;pyximport.install()>>>importhelloworldHello World
This allows you to automatically run Cython on every.pyx
thatPython is trying to import. You should use this for simple Cythonbuilds only where no extra C libraries and no special building setupis needed.
It is also possible to compile new.py
modules that are beingimported (including the standard library and installed packages). Forusing this feature, just tell that topyximport
:
>>>pyximport.install(pyimport=True)
In the case that Cython fails to compile a Python module,pyximport
will fall back to loading the source modules instead.
Note that it is not recommended to letpyximport
build codeon end user side as it hooks into their import system. The best wayto cater for end users is to provide pre-built binary packages in thewheel packaging format.
Arguments¶
The functionpyximport.install()
can take several arguments toinfluence the compilation of Cython or Python files.
- pyximport.install(pyximport=True,pyimport=False,build_dir=None,build_in_temp=True,setup_args=None,reload_support=False,load_py_module_on_import_failure=False,inplace=False,language_level=None)¶
Main entry point for pyxinstall.
Call this to install the
.pyx
import hook inyour meta-path for a single Python process. If you want it to beinstalled whenever you use Python, add it to yoursitecustomize
(as described above).- Parameters:
pyximport – If set to False, does not try to import
.pyx
files.pyimport – You can pass
pyimport=True
to alsoinstall the.py
import hookin your meta-path. Note, however, that it is rather experimental,will not work at all for some.py
files and packages, and willheavily slow down your imports due to search and compilation.Use at your own risk.build_dir – By default, compiled modules will end up in a
.pyxbld
directory in the user’s home directory. Passing a different pathasbuild_dir
will override this.build_in_temp – If
False
, will produce the C files locally. Workingwith complex dependencies and debugging becomes more easy. Thiscan principally interfere with existing files of the same name.setup_args – Dict of arguments for Distribution.See
distutils.core.setup()
.reload_support – Enables support for dynamic
reload(my_module)
, e.g. after a change in the Cython code.Additional files<so_path>.reloadNN
may arise on that account, whenthe previously loaded module file cannot be overwritten.load_py_module_on_import_failure – If the compilation of a
.py
file succeeds, but the subsequent import fails for some reason,retry the import with the normal.py
module instead of thecompiled module. Note that this may lead to unpredictable resultsfor modules that change the system state during their import, asthe second import will rerun these modifications in whatever statethe system was left after the import of the compiled modulefailed.inplace – Install the compiled module(
.so
for Linux and Mac /.pyd
for Windows)next to the source file.language_level – The source language level to use: 2 or 3.The default is to use the language level of the current Pythonruntime for .py files and Py2 for
.pyx
files.
Dependency Handling¶
Sincepyximport
does not usecythonize()
internally, it currentlyrequires a different setup for dependencies. It is possible to declare thatyour module depends on multiple files, (likely.h
and.pxd
files).If your Cython module is namedfoo
and thus has the filenamefoo.pyx
then you should create another file in the same directorycalledfoo.pyxdep
. Themodname.pyxdep
file can be a list offilenames or “globs” (like*.pxd
orinclude/*.h
). Each filename orglob must be on a separate line. Pyximport will check the file date for eachof those files before deciding whether to rebuild the module. In order tokeep track of the fact that the dependency has been handled, Pyximport updatesthe modification time of your “.pyx” source file. Future versions may dosomething more sophisticated like informing setuptools of the dependenciesdirectly.
Limitations¶
pyximport
does not usecythonize()
. Thus it is notpossible to do things like using compiler directives atthe top of Cython files or compiling Cython code to C++.
Pyximport does not give you any control over how your Cython file iscompiled. Usually the defaults are fine. You might run into problems ifyou wanted to write your program in half-C, half-Cython and build theminto a single library.
Pyximport does not hide the setuptools/GCC warnings and errors generatedby the import process. Arguably this will give you better feedback ifsomething went wrong and why. And if nothing went wrong it will give youthe warm fuzzy feeling that pyximport really did rebuild your module as itwas supposed to.
Basic module reloading support is available with the optionreload_support=True
.Note that this will generate a new module filename for each build and thusend up loading multiple shared libraries into memory over time. CPython has limitedsupport for reloading shared libraries as such,seePEP 489.
Pyximport puts both your.c
file and the platform-specific binary intoa separate build directory, usually$HOME/.pyxblx/
. To copy it backinto the package hierarchy (usually next to the source file) for manualreuse, you can pass the optioninplace=True
.
Compiling withcython.inline
¶
One can also compile Cython in a fashion similar to SciPy’sweave.inline
.For example:
>>>importcython>>>deff(a):...ret=cython.inline("return a+b",b=3)...
Unbound variables are automatically pulled from the surrounding localand global scopes, and the result of the compilation is cached forefficient reuse.
Compiling withcython.compile
¶
Cython supports transparent compiling of the cython code in a function using the@cython.compile
decorator:
@cython.compiledefplus(a,b):returna+b
Parameters of the decorated function cannot have type declarations. Their types areautomatically determined from values passed to the function, thus leading to one or morespecialised compiled functions for the respective argument types.Executing example:
importcython@cython.compiledefplus(a,b):returna+bprint(plus('3','5'))print(plus(3,5))
will produce following output:
358
Compiling with Sage¶
The Sage notebook allows transparently editing and compiling Cythoncode simply by typing%cython
at the top of a cell and evaluateit. Variables and functions defined in a Cython cell are imported into therunning session. Please checkSage documentation for details.
You can tailor the behavior of the Cython compiler by specifying thedirectives below.
Compiling with a Jupyter Notebook¶
It’s possible to compile code in a notebook cell with Cython.For this you need to load the Cython magic:
%load_extcython
Then you can define a Cython cell by writing%%cython
on top of it.Like this:
%%cythoncdefinta=0foriinrange(10):a+=iprint(a)
Note that each cell will be compiled into a separate extension module. So if you use a package in a Cythoncell, you will have to import this package in the same cell. It’s not enough tohave imported the package in a previous cell. Cython will tell you that there are“undefined global names” at compilation time if you don’t comply.
The global names (top level functions, classes, variables and modules) of thecell are then loaded into the global namespace of the notebook. So in theend, it behaves as if you executed a Python cell.
Additional allowable arguments to the Cython magic are listed below.You can see them also by typing`%%cython?
in IPython or a Jupyter notebook.
-a, –annotate | Produce a colorized HTML version of the source. |
–annotate-fullc | Produce a colorized HTML version of the source which includes entire generated C/C++-code. |
-+, –cplus | Output a C++ rather than C file. |
-f, –force | Force the compilation of a new module, even if the source has been previously compiled. |
-3 | Select Python 3 syntax |
-2 | Select Python 2 syntax |
-c=COMPILE_ARGS, –compile-args=COMPILE_ARGS | Extra flags to pass to compiler via the extra_compile_args. |
–link-args LINK_ARGS | Extra flags to pass to linker via the extra_link_args. |
-l LIB, –lib LIB | Add a library to link the extension against (can be specified multiple times). |
-L dir | Add a path to the list of library directories (can be specified multiple times). |
-I INCLUDE, –include INCLUDE | Add a path to the list of include directories (can be specified multiple times). |
-S, –src | Add a path to the list of src files (can be specified multiple times). |
-n NAME, –name NAME | Specify a name for the Cython module. |
–pgo | Enable profile guided optimisation in the C compiler. Compiles the cell twice and executes it in between to generate a runtime profile. |
–verbose | Print debug information like generated .c/.cpp file location and exact gcc/g++ command invoked. |
Cython cache¶
The Cython cache is used to store cythonized.c
/.cpp
files to avoid running the Cython compiler on the files which were cythonized before.
Note
Only.c
/.cpp
files are cached. The C compiler is run every time. To avoid executing C compiler a tool like ccache needs to be used.
The Cython cache is disabled by default but can be enabled by thecache
parameter ofcythonize()
:
fromsetuptoolsimportsetup,ExtensionfromCython.Buildimportcythonizeextensions=[Extension("*",["lib.pyx"]),]setup(name="hello",ext_modules=cythonize(extensions,cache=True))
The cached files are searched in the following paths by default in the following order:
path specified in the
CYTHON_CACHE_DIR
environment variable,~/Library/Caches/Cython
on MacOS and$XDG_CACHE_HOME/cython
on POSIX if theXDG_CACHE_HOME
environment variable is defined,otherwise
~/.cython
.
Compiler options¶
Compiler options can be set in thesetup.py
, before callingcythonize()
,like this:
fromsetuptoolsimportsetupfromCython.BuildimportcythonizefromCython.CompilerimportOptionsOptions.docstrings=Falsesetup(name="hello",ext_modules=cythonize("lib.pyx"),)
Here are the options that are available:
- Cython.Compiler.Options.docstrings=True¶
Whether or not to include docstring in the Python extension. If False, the binary sizewill be smaller, but the
__doc__
attribute of any class or function will be anempty string.
- Cython.Compiler.Options.embed_pos_in_docstring=False¶
Embed the source code position in the docstrings of functions and classes.
- Cython.Compiler.Options.generate_cleanup_code=False¶
Decref global variables in each module on exit for garbage collection.0: None, 1+: interned objects, 2+: cdef globals, 3+: types objectsMostly for reducing noise in Valgrind as it typically executes at process exit(when all memory will be reclaimed anyways).Note that directly or indirectly executed cleanup code that makes use of globalvariables or types may no longer be safe when enabling the respective level sincethere is no guaranteed order in which the (reference counted) objects willbe cleaned up. The order can change due to live references and reference cycles.
- Cython.Compiler.Options.clear_to_none=True¶
Should tp_clear() set object fields to None instead of clearing them to NULL?
- Cython.Compiler.Options.annotate=False¶
Generate an annotated HTML version of the input source files for debugging and optimisation purposes.This has the same effect as the
annotate
argument incythonize()
.
- Cython.Compiler.Options.fast_fail=False¶
This will abort the compilation on the first error occurred rather than tryingto keep going and printing further error messages.
- Cython.Compiler.Options.warning_errors=False¶
Turn all warnings into errors.
- Cython.Compiler.Options.error_on_unknown_names=True¶
Make unknown names an error. Python raises a NameError whenencountering unknown names at runtime, whereas this option makesthem a compile time error. If you want full Python compatibility,you should disable this option and also ‘cache_builtins’.
- Cython.Compiler.Options.error_on_uninitialized=True¶
Make uninitialized local variable reference a compile time error.Python raises UnboundLocalError at runtime, whereas this option makesthem a compile time error. Note that this option affects only variablesof “python object” type.
- Cython.Compiler.Options.convert_range=True¶
This will convert statements of the form
foriinrange(...)
toforifrom...
wheni
is a C integer type, and the direction(i.e. sign of step) can be determined.WARNING: This may change the semantics if the range causes assignment toi to overflow. Specifically, if this option is set, an error will beraised before the loop is entered, whereas without this option the loopwill execute until an overflowing value is encountered.
- Cython.Compiler.Options.cache_builtins=True¶
Perform lookups on builtin names only once, at module initialisationtime. This will prevent the module from getting imported if abuiltin name that it uses cannot be found during initialisation.Default is True.Note that some legacy builtins are automatically remappedfrom their Python 2 names to their Python 3 names by Cythonwhen building in Python 3.x,so that they do not get in the way even if this option is enabled.
- Cython.Compiler.Options.gcc_branch_hints=True¶
Generate branch prediction hints to speed up error handling etc.
- Cython.Compiler.Options.lookup_module_cpdef=False¶
Enable this to allow one to write
your_module.foo=...
to overwrite thedefinition of the cpdef function foo, at the cost of an extra dictionarylookup on every call.If this is false it generates only the Python wrapper and no override check.
- Cython.Compiler.Options.embed=None¶
Whether or not to embed the Python interpreter, for use in making astandalone executable or calling from external libraries.This will provide a C function which initialises the interpreter andexecutes the body of this module.Seethis demofor a concrete example.If true, the initialisation function is the C main() function, butthis option can also be set to a non-empty string to provide a function name explicitly.Default is False.
- Cython.Compiler.Options.cimport_from_pyx=False¶
Allows cimporting from a pyx file without a pxd file.
- Cython.Compiler.Options.buffer_max_dims=8¶
Maximum number of dimensions for buffers – set lower than number ofdimensions in numpy, asslices are passed by value and involve a lot of copying.
- Cython.Compiler.Options.closure_freelist_size=8¶
Number of function closure instances to keep in a freelist (0: no freelists)
Compiler directives¶
Compiler directives are instructions which affect the behavior ofCython code. Here is the list of currently supported directives:
binding
(True / False),default=TrueControls whether free functions behave more like Python’s CFunctions(e.g.
len()
) or, when set to True, more like Python’s functions.When enabled, functions will bind to an instance when looked up as aclass attribute (hence the name) and will emulate the attributesof Python functions, including introspections like argument names andannotations.Changed in version 3.0.0:Default changed from False to True
boundscheck
(True / False),default=TrueIf set to False, Cython is free to assume that indexing operations([]-operator) in the code will not cause any IndexErrors to beraised. Lists, tuples, and strings are affected only if the indexcan be determined to be non-negative (or if
wraparound
is False).Conditions which would normally trigger an IndexError may instead causesegfaults or data corruption if this is set to False.wraparound
(True / False),default=TrueIn Python, arrays and sequences can be indexed relative to the end.For example, A[-1] indexes the last value of a list.In C, negative indexing is not supported.If set to False, Cython is allowed to neither check for nor correctlyhandle negative indices, possibly causing segfaults or data corruption.If bounds checks are enabled (the default, see
boundschecks
above),negative indexing will usually raise anIndexError
for indices thatCython evaluates itself.However, these cases can be difficult to recognise in user code todistinguish them from indexing or slicing that is evaluated by theunderlying Python array or sequence object and thus continues to supportwrap-around indices.It is therefore safest to apply this option only to code that does notprocess negative indices at all.initializedcheck
(True / False),default=True- If set to True, Cython checks that
a memoryview is initialized whenever its elements are accessedor assigned to.
a C++ class is initialized when it is accessed(only when
cpp_locals
is on)
Setting this to False disables these checks.
nonecheck
(True / False),default=FalseIf set to False, Cython is free to assume that native fieldaccesses on variables typed as an extension type, or bufferaccesses on a buffer variable, never occurs when the variable isset to
None
. Otherwise a check is inserted and theappropriate exception is raised. This is off by default forperformance reasons.freethreading_compatible
(True / False),default=FalseIf set to True, Cython sets the
Py_mod_gil
slot toPy_MOD_GIL_NOT_USED
to signal that the module is safe to runwithout an active GIL and prevent the GIL from being enabledwhen the module is imported. Otherwise the slot is set toPy_MOD_GIL_USED
which will cause the GIL to be automaticallyenabled. Setting this to True does not itself make the module safeto run without the GIL; it merely confirms that you have checkedthe logic and consider it safe to run. Since free-threading supportis still experimental itself, this is also an experimental directive thatmight be changed or removed in future releases.subinterpreters_compatible
(no / shared_gil / own_gil),default=noIf set to
shared_gil
orown_gil
, then Cython sets thePy_mod_multiple_interpreters
slot toPy_MOD_MULTIPLE_INTERPRETERS_SUPPORTED
orPy_MOD_PER_INTERPRETER_GIL_SUPPORTED
respectively to signal thatthe module is safe to run in isolated subinterpreters. Setting this optiondoes not itself make the module safe to run in isolated subinterpreters;it merely confirms that you have checked the logic and consider it safe to run.Currentlycdef
global variables (especially when the type is a Python object) andacquiring the GIL (but notre-acquiring the GIL) are known not to workcorrectly and will generate warnings at compile time.overflowcheck
(True / False),default=FalseIf set to True, raise errors on overflowing C integer arithmeticoperations. Incurs a modest runtime penalty, but is much faster thanusing Python ints.
overflowcheck.fold
(True / False),default=TrueIf set to True, and overflowcheck is True, check the overflow bit fornested, side-effect-free arithmetic expressions once rather than at everystep. Depending on the compiler, architecture, and optimization settings,this may help or hurt performance. A simple suite of benchmarks can befound in
Demos/overflow_perf.pyx
.embedsignature
(True / False),default=FalseIf set to True, Cython will embed a textual copy of the callsignature in the docstring of all Python visible functions andclasses. Tools like IPython and epydoc can thus display thesignature, which cannot otherwise be retrieved aftercompilation.
embedsignature.format
(c
/python
/clinic
),default=”c”If set to
c
, Cython will generate signatures preservingC type declarations and Python type annotations.If set topython
, Cython will do a best attempt to usepure-Python type annotations in embedded signatures. For argumentswithout Python type annotations, the C type is mapped to theclosest Python type equivalent (e.g., Cshort
is mapped toPythonint
type and Cdouble
is mapped to Pythonfloat
type). The specific output and type mapping are experimental andmay change over time.Theclinic
format generates signatures that are compatiblewith those understood by CPython’s Argument Clinic tool. TheCPython runtime strips these signatures from docstrings andtranslates them into a__text_signature__
attribute. This ismainly useful when usingbinding=False
, since the Cythonfunctions generated withbinding=True
do not have (nor need)a__text_signature__
attribute.cdivision
(True / False),default=FalseIf set to False, Cython will adjust the remainder and quotientoperators C types to match those of Python ints (which differ whenthe operands have opposite signs) and raise a
ZeroDivisionError
when the right operand is 0. This has up toa 35% speed penalty. If set to True, no checks are performed. SeeCEP 516.cdivision_warnings
(True / False),default=FalseIf set to True, Cython will emit a runtime warning wheneverdivision is performed with negative operands. SeeCEP 516.
cpow
(True / False),default=Falsecpow
modifies the return type ofa**b
, as shown in thetable below:cpow behaviour¶ Type of
a
Type of
b
cpow==True
cpow==False
C integer
Negative integer compile-time constant
Return type is C double
Return type is C double (special case)
C integer
C integer (known to be >= 0 at compile time)
Return type is integer
Return type is integer
C integer
C integer (may be negative)
Return type is integer
Return type is C double (note that Python would dynamically pick
int
orfloat
here, while Cython doesn’t)C floating point
C integer
Return type is floating point
Return type is floating point
C floating point (or C integer)
C floating point
Return type is floating point, result is NaN if the result would be complex
Either a C real or complex number at cost of some speed
The
cpow==True
behaviour largely keeps the result type thesame as the operand types, while thecpow==False
behaviourfollows Python and returns a flexible type depending on theinputs.Introduced in Cython 3.0 with a default of False;before that, the behaviour matched the
cpow=True
version.always_allow_keywords
(True / False),default=TrueWhen disabled, uses the
METH_NOARGS
andMETH_O
signatures whenconstructing functions/methods which take zero or one arguments. Has noeffect on special methods and functions with more than one argument. TheMETH_NOARGS
andMETH_O
signatures provide slightly fastercalling conventions but disallow the use of keywords.c_api_binop_methods
(True / False),default=FalseWhen enabled, makes the special binary operator methods (
__add__
, etc.)behave according to the low-level C-API slot semantics, i.e. only a singlemethod implements both the normal and reversed operator. This used to bethe default in Cython 0.x and was now replaced by Python semantics, i.e. thedefault in Cython 3.x and later isFalse
.profile
(True / False),default=FalseWrite hooks for Python profilers into the compiled C code.Whether the generated module actually uses profiling depends onthe value of the C macro
CYTHON_PROFILE
which is1
bydefault but which you can optionally set to0
to turn off theprofiling code at C compile-time. DefineCYTHON_USE_SYS_MONITORING
to either 1 or 0 to control the mechanism used to implement profilingon Python 3.13 and above. Note that neitherprofile
norlinetrace
work with any tool that usessys.monitoring
on Python 3.12.linetrace
(True / False),default=FalseWrite line tracing hooks for Python profilers or coverage reportinginto the compiled C code. This also enables profiling.Note that the generated module will not actually use linetracing, unless you additionally pass the C macro definition
CYTHON_TRACE=1
to the C compiler (e.g. using the setuptools optiondefine_macros
). DefineCYTHON_TRACE_NOGIL=1
to also includenogil
functions and sections. DefineCYTHON_USE_SYS_MONITORING
to either 1 or 0 to control the mechanism used to implement thesefeatures on Python 3.13 and above. Note that neitherprofile
norlinetrace
work with any tool that usessys.monitoring
on Python 3.12.infer_types
(True / False),default=NoneInfer types of untyped variables in function bodies. Default isNone, indicating that only safe (semantically-unchanging) inferencesare allowed.In particular, inferringintegral types for variablesused in arithmeticexpressions is considered unsafe (due to possible overflow) and must beexplicitly requested.
language_level
(2/3/3str),default=NoneGlobally set the Python language level to be used for module compilation.Default is None, indicating compatibility with Python 3 in Cython 3.x and with Python 2in Cython 0.x. To enable Python 3 source code semantics, set this to 3 (or 3str) at the startof a module or pass the “-3” or “–3str” command line options to thecompiler. For Python 2 semantics, use 2 and “-2” accordingly.Before Cython 3.1, the
3str
option enabled Python 3 semantics but didnot change thestr
type and unprefixed string literals tounicode
when the compiled code runs in Python 2.x.In Cython 3.1,3str
is an alias for3
.Language level 2 ignoresx:int
type annotations due to the int/long ambiguity.Note that cimported files inherit this setting from the modulebeing compiled, unless they explicitly set their own language level.Included source files always inherit this setting.c_string_type
(bytes / str / unicode),default=bytesGlobally set the type of an implicit coercion from char* or std::string.
c_string_encoding
(ascii, default, utf-8, etc.),default=””Globally set the encoding to use when implicitly coercing char* or std:stringto a unicode object. Coercion from a unicode object to C type is only allowedwhen set to
ascii
ordefault
, the latter being utf-8 in Python 3 andnearly-always ascii in Python 2.type_version_tag
(True / False),default=TrueEnables the attribute cache for extension types in CPython by setting thetype flag
Py_TPFLAGS_HAVE_VERSION_TAG
. Default is True, meaning thatthe cache is enabled for Cython implemented types. To disable itexplicitly in the rare cases where a type needs to juggle with itstp_dict
internally without paying attention to cache consistency, this option canbe set to False. Note that this no longer applies to Python 3.11 and later.unraisable_tracebacks
(True / False),default=FalseWhether to print tracebacks when suppressing unraisable exceptions.
iterable_coroutine
(True / False),default=FalsePEP 492 specifies that async-defcoroutines must not be iterable, in order to prevent accidental misuse innon-async contexts. However, this makes it difficult and inefficient to writebackwards compatible code that uses async-def coroutines in Cython but needs tointeract with async Python code that uses the older yield-from syntax, such asasyncio before Python 3.5. This directive can be applied in modules orselectively as decorator on an async-def coroutine to make the affectedcoroutine(s) iterable and thus directly interoperable with yield-from.
annotation_typing
(True / False),default=TrueUses function argument annotations to determine the type of variables.Since Python does not enforce types given inannotations, setting to False gives greater compatibility with Python code.From Cython 3.0,
annotation_typing
can be set on a per-function orper-class basis.emit_code_comments
(True / False),default=TrueCopy the original source code line by line into C code comments in the generatedcode file to help with understanding the output.This is also required for coverage analysis.
cpp_locals
(True / False),default=FalseMake C++ variables behave more like Python variables by allowing them to be“unbound” instead of always default-constructing them at the start of afunction. Seecpp_locals directive for more detail.
legacy_implicit_noexcept
(True / False),default=FalseWhen enabled,
cdef
functions will not propagate raised exceptions by default. Hence,the function will behave in the same way as if declared withnoexcept keyword. SeeError return values for details. Setting this directive toTrue
willcause Cython 3.0 to have the same semantics as Cython 0.x. This directive was solely addedto help migrate legacy code written before Cython 3. It will be removed in a future release.
Configurable optimisations¶
optimize.use_switch
(True / False),default=TrueWhether to expand chained if-else statements (including statements like
ifx==1orx==2:
) into C switch statements. This can have performancebenefits if there are lots of values but cause compiler errors if there are anyduplicate values (which may not be detectable at Cython compile time for allC constants).optimize.unpack_method_calls
(True / False),default=TrueCython can generate code that optimistically checks for Python method objectsat call time and unpacks the underlying function to call it directly. Thiscan substantially speed up method calls, especially for builtins, but may alsohave a slight negative performance impact in some cases where the guess goescompletely wrong.Disabling this option can also reduce the code size.
Warnings¶
All warning directives take True / False as optionsto turn the warning on / off.
warn.undeclared
(default False)Warns about any variables that are implicitly declared without a
cdef
declarationwarn.unreachable
(default True)Warns about code paths that are statically determined to be unreachable, e.g.returning twice unconditionally.
warn.maybe_uninitialized
(default False)Warns about use of variables that are conditionally uninitialized.
warn.unused
(default False)Warns about unused variables and declarations
warn.unused_arg
(default False)Warns about unused function arguments
warn.unused_result
(default False)Warns about unused assignment to the same name, such as
r=2;r=1+2
warn.multiple_declarators
(default True)Warns about multiple variables declared on the same line with at least one pointer type.For example
cdefdouble*a,b
- which, as in C, declaresa
as a pointer,b
asa value type, but could be mininterpreted as declaring two pointers.warn.deprecated.DEF
(default False)Warns about use of the deprecated
DEF
statement in Cython code, seeConditional Compilation andDeprecation of DEF / IF.warn.deprecated.IF
(default True)Warns about use of the deprecated
IF
statement in Cython code, seeConditional Compilation andDeprecation of DEF / IF.show_performance_hints
(default True)Show performance hints during compilation pointing to places in the code which can yield performance degradation.Note that performance hints are not warnings and hence the directives starting with
warn.
above do not affect themand they will not trigger a failure when “error on warnings” is enabled.
How to set directives¶
Globally¶
One can set compiler directives through a special header comment near the top of the file, like this:
# cython: language_level=3, boundscheck=False
The comment must appear before any code (but can appear after othercomments or whitespace).
One can also pass a directive on the command line by using the -X switch:
$cython-Xboundscheck=True...
Directives passed on the command line will override directives set inheader comments.
Locally¶
For local blocks, you need to cimport the special builtincython
module:
#!pythoncimportcython
Then you can use the directives either as decorators or in a withstatement, like this:
#!python@cython.boundscheck(False)# turn off boundscheck for this functiondeff():...# turn it temporarily on again for this blockwithcython.boundscheck(True):...
Warning
These two methods of setting directives arenotaffected by overriding the directive on the command-line using the-X option.
Insetup.py
¶
Compiler directives can also be set in thesetup.py
file by passing a keywordargument tocythonize
:
fromsetuptoolsimportsetupfromCython.Buildimportcythonizesetup(name="My hello app",ext_modules=cythonize('hello.pyx',compiler_directives={'embedsignature':True}),)
This will override the default directives as specified in thecompiler_directives
dictionary.Note that explicit per-file or local directives as explained above take precedence over thevalues passed tocythonize
.
C line numbers in tracebacks¶
To provide more detailed debug information, Python tracebacks of Cython modulesshow the C line where the exception originated (or was propagated). This feature is notentirely for free and can visibly increase the C compile time as well as adding 0-5% to thesize of the binary extension module. It is therefore disabled in Cython 3.1 and can be controlled using C macros.
CYTHON_CLINE_IN_TRACEBACK=1
always shows the C line number in tracebacks,CYTHON_CLINE_IN_TRACEBACK=0
never shows the C line number in tracebacks,
Unless the feature is disabled completely with this macro, there is also support for enabling and disablingthe feature at runtime, at the before mentioned cost of longer C compile times and larger extension modules.This can be configured with the C macro
CYTHON_CLINE_IN_TRACEBACK_RUNTIME=1
To then change the behaviour at runtime, you can import the special modulecython_runtime
after loading a Cython module and set the attributecline_in_traceback
in that moduleto either true or false to control the behaviour as your Cython code is being run:
importcython_runtimecython_runtime.cline_in_traceback=TrueraiseValueError(5)
If both macros arenot defined by the build setup orCFLAGS
, the feature is disabled.
In Cython 3.0 and earlier, the Cython compiler optionc_line_in_traceback
(passed asan argument tocythonize
insetup.py
) or the commandline argument--no-c-in-traceback
could also be used to disable this feature.From Cython 3.1, this is still possible, but should be migrated to using the C macros instead.Before Cython 3.1, theCYTHON_CLINE_IN_TRACEBACK
macro already works as describedbut the Cython option is needed to remove the compile-time cost.
C macro defines¶
Cython has a number of C macros that can be used to control compilation. Typically, thesewould be set usingextra_compile_args
insetup.py (for exampleextra_compile_args=['-DCYTHON_USE_TYPE_SPECS=1']
), however they can also be set inother ways like using theCFLAGS
environmental variable.
These macros are set automatically by Cython to sensible default values unlessyou chose to explicitly override them, so they are a tool that most userscan happily ignore. Not all combinations of macros are compatible or tested, andsome change the default value of other macros. They are listed below in rough order frommost important to least important:
Py_LIMITED_API
Turns on Cython’s Limited API support, meaning that one compiled modulecan be used by many Python interpreter versions (at the cost of some performance).At this stage many features do not work in the Limited API. You should set thismacro to be the version hex for theminimum Python version you want to support (>=3.8).
0x03080000
will supportPython 3.8 upwards.Note that this is aPythonmacro
,rather than just a Cython macro, and so it changes what parts of the Python headersare visible too. SeeThe Limited API and Stable ABI for more details about this feature.CYTHON_PEP489_MULTI_PHASE_INIT
Uses multi-phase module initialization as described inPEP 489. This improvesPython compatibility, especially when running the initial import of the code when itmakes attributes such as
__file__
available. It is therefore on by defaultwhere supported.CYTHON_USE_MODULE_STATE
Stores module data on a struct associated with the module object rather than asC global variables. The advantage is that it should be possible to import thesame module more than once (e.g. in different sub-interpreters). At the momentthis is experimental and not all data has been moved. Specifically,
cdef
globals have not been moved.CYTHON_USE_TYPE_SPECS
Defines
cdefclass
es asHeap Types rather than“static types”. Practically this does not change a lot from a userpoint of view, but it is needed to implement Limited API support.CYTHON_PROFILE
,CYTHON_TRACE
,CYTHON_TRACE_NOGIL
These control the inclusion of profiling and line tracing calls in the module.See the
profile
andlinetrace
Compiler directives.CYTHON_PROFILE
is on by default; theCYTHON_TRACE
macros areoff by default.CYTHON_USE_SYS_MONITORING
On Python 3.13+ this selects the newsys.monitoringmechanism for profiling and linetracing. It is on by default, but can be set to 0to force use of the old mechanism. Some tools still require the old mechanism,most notably “Coverage” (as of 2025).
CYTHON_EXTERN_C
Slightly different to the other macros, this controls how
cdefpublic
functions appear to C++ code. SeeC++ public declarations for full details.CYTHON_CLINE_IN_TRACEBACK
Controls whether C lines numbers appear in tracebacks.SeeC line numbers in tracebacks for a complete description.
CYTHON_CCOMPLEX
Passes complex numbers using the C or C++ language standard library typesinstead of an internal type defined by Cython. Turning it onmaximizes compatibility with external libraries. However, MSVChas poor standards support (especially in C mode) and so struggles touse the standard library types. It is on by default on platformswhere we think it’s likely to work.
CYTHON_COMPRESS_STRINGS
Store Python strings in the binary module as compressed data, decompressing themat import time. By default,
zlib
compression is used (CYTHON_COMPRESS_STRINGS=1
).Set to0
to disable compression or to2
to selectbzip2
compression.Note that the respective standard library decompression module must be availableat module import time, or the import will fail.compression.zstd
can be selected withCYTHON_COMPRESS_STRINGS=3
but is onlyavailable in the standard library in Python 3.14 and later. Cython will thenfall back tozlib
when compiling in older Python versions.CYTHON_IMMORTAL_CONSTANTS
Makes cached constants (e.g. strings, tuples, ints, floats, slices) immortal,in Python versions that support immortality. This is most useful whenthe constants are used in many different threads because it avoids most writesto the constants due to reference counting. Disabled by default, but enabledin free-threaded builds.
There is a further list of macros which turn off various optimizations or languagefeatures. Under normal circumstance Cython enables these automatically based on theversion of Python you are compiling for so there is no need to use themto try to enable extra optimizations - all supported optimizations are enabled bydefault. These are mostly relevant if you’re tying to get Cython working in anew and unsupported Python interpreter where you will typically want to setthem to 0 todisable optimizations. They are listed below for completeness buthidden by default since most users will be uninterested in changing them.
CYTHON_USE_TYPE_SLOTS
If enabled, Cython will directly access members of the
PyTypeObject
struct.CYTHON_USE_PYTYPE_LOOKUP
Use the internal_PyType_Lookup() function for more efficient accessto properties of C classes.
CYTHON_USE_PYLONG_INTERNALS
/CYTHON_USE_PYLIST_INTERNALS
/CYTHON_USE_UNICODE_INTERNALS
Enable optimizations based on direct access into the internals of Python
int
/list
/unicode
objects respectively.CYTHON_USE_UNICODE_WRITER
Use a faster (but internal) mechanism for building unicode strings, forexample in f-strings.
CYTHON_AVOID_BORROWED_REFS
Avoid using “borrowed references” and ensure that Cython always holdsa reference to objects it manipulates. Most useful fornon-reference-counted implementations of Python, like PyPy(where it is enabled by default).
CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS
Avoid using APIs that return unsafe “borrowed references” and instead usethe equivalent APIs that return “strong references”. Most useful forthe free-threaded build of CPython, where incrementing the referencecount of borrowed references to items in mutable containers mightintroduce thread safety issues. Borrowed references to items in immutablecontainers are still allowed with this setting.
CYTHON_ASSUME_SAFE_MACROS
Use some C-API macros that increase performance by skipping error checking,which may not be safe on all Python implementations (e.g. PyPy).
CYTHON_ASSUME_SAFE_SIZE
Prefer the
Py*_GET_SIZE()
C-API macros / inline-functions for builtin typesover theirPy*_GetSize()
counterparts if errors are not expected.CYTHON_FAST_GIL
On some Python versions this speeds up getting/releasing the GIL.
CYTHON_UNPACK_METHODS
Try to speed up method calls at the cost of code-size. Linked tothe
optimize.unpack_method_calls
compiler directive - this macrois used to selectively enable the compiler directive only on versionsof Python that support it.CYTHON_METH_FASTCALL
/CYTHON_FAST_PYCALL
These are used internally to incrementally enable the vectorcall callingmechanism on older Python versions (<3.8).
CYTHON_PEP487_INIT_SUBCLASS
EnablePEP 487
__init_subclass__
behaviour.CYTHON_USE_TP_FINALIZE
Use the
tp_finalize
type-slot instead oftp_dealloc
,as described inPEP 442.CYTHON_USE_DICT_VERSIONS
Try to optimize attribute lookup by using versioned dictionarieswhere supported.
CYTHON_USE_EXC_INFO_STACK
Use an internal structure to track exception state,used in CPython 3.7 and later.
CYTHON_UPDATE_DESCRIPTOR_DOC
Attempt to provide docstrings also for special (double underscore) methods.
CYTHON_USE_FREELISTS
Enable the use of freelists on extension types withthe @cython.freelist decorator.
CYTHON_ATOMICS
Enable the use of atomic reference counting (as opposed to locking thenreference counting) in Cython typed memoryviews.
CYTHON_DEBUG_VISIT_CONST
Debug option for including constant (string/integer/code/…) objects in
gc.get_referents()
.By default, Cython avoids GC traversing these objects because they can never participatein reference cycles, and thus would uselessly waste time during garbage collection runs.CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE
Makes module state lookup thread-safe (when
CYTHON_USE_MODULE_STATE
andCYTHON_PEP489_MULTI_PHASE_INIT
are both enabled). This is on by defaultwhere it would be helpful, however it can be disabled if you are sure thatone interpreter will not be importing your module at the same time as anotheris using it. Values greater than 1 can be used to select a specific implementationfor debugging purposes.