241 lines
6.4 KiB
ReStructuredText
241 lines
6.4 KiB
ReStructuredText
Getting started
|
|
===============
|
|
|
|
Here you will learn some basic things you need to know to get started with mypyc.
|
|
|
|
Prerequisites
|
|
-------------
|
|
|
|
You need a Python C extension development environment. The way to set this up
|
|
depends on your operating system.
|
|
|
|
macOS
|
|
*****
|
|
|
|
Install Xcode command line tools:
|
|
|
|
.. code-block::
|
|
|
|
$ xcode-select --install
|
|
|
|
Linux
|
|
*****
|
|
|
|
You need a C compiler and CPython headers and libraries. The specifics
|
|
of how to install these varies by distribution. Here are instructions for
|
|
Ubuntu 18.04, for example:
|
|
|
|
.. code-block::
|
|
|
|
$ sudo apt install python3-dev
|
|
|
|
Windows
|
|
*******
|
|
|
|
Install `Visual C++ <https://www.visualstudio.com/downloads/#build-tools-for-visual-studio-2017>`_.
|
|
|
|
Installation
|
|
------------
|
|
|
|
Mypyc is shipped as part of the mypy distribution. Install mypy like
|
|
this (you need Python 3.5 or later):
|
|
|
|
.. code-block::
|
|
|
|
$ python3 -m pip install -U mypy
|
|
|
|
On some systems you need to use this instead:
|
|
|
|
.. code-block::
|
|
|
|
$ python -m pip install -U mypy
|
|
|
|
Example program
|
|
---------------
|
|
|
|
Let's start with a classic micro-benchmark, recursive fibonacci. Save
|
|
this file as ``fib.py``:
|
|
|
|
.. code-block:: python
|
|
|
|
import time
|
|
|
|
def fib(n: int) -> int:
|
|
if n <= 1:
|
|
return n
|
|
else:
|
|
return fib(n - 2) + fib(n - 1)
|
|
|
|
t0 = time.time()
|
|
fib(32)
|
|
print(time.time() - t0)
|
|
|
|
Note that we gave the ``fib`` function a type annotation. Without it,
|
|
performance won't be as impressive after compilation.
|
|
|
|
.. note::
|
|
|
|
`Mypy documentation
|
|
<https://mypy.readthedocs.io/en/stable/index.html>`_ is a good
|
|
introduction if you are new to type annotations or mypy. Mypyc uses
|
|
mypy to perform type checking and type inference, so some familiarity
|
|
with mypy is very useful.
|
|
|
|
Compiling and running
|
|
---------------------
|
|
|
|
We can run ``fib.py`` as a regular, interpreted program using CPython:
|
|
|
|
.. code-block:: console
|
|
|
|
$ python3 fib.py
|
|
0.4125328063964844
|
|
|
|
It took about 0.41s to run on my computer.
|
|
|
|
Run ``mypyc`` to compile the program to a binary C extension:
|
|
|
|
.. code-block:: console
|
|
|
|
$ mypyc fib.py
|
|
|
|
This will generate a C extension for ``fib`` in the current working
|
|
directory. For example, on a Linux system the generated file may be
|
|
called ``fib.cpython-37m-x86_64-linux-gnu.so``.
|
|
|
|
Since C extensions can't be run as programs, use ``python3 -c`` to run
|
|
the compiled module as a program:
|
|
|
|
.. code-block:: console
|
|
|
|
$ python3 -c "import fib"
|
|
0.04097270965576172
|
|
|
|
After compilation, the program is about 10x faster. Nice!
|
|
|
|
.. note::
|
|
|
|
``__name__`` in ``fib.py`` would now be ``"fib"``, not ``"__main__"``.
|
|
|
|
You can also pass most
|
|
`mypy command line options <https://mypy.readthedocs.io/en/stable/command_line.html>`_
|
|
to ``mypyc``.
|
|
|
|
Deleting compiled binary
|
|
------------------------
|
|
|
|
You can manually delete the C extension to get back to an interpreted
|
|
version (this example works on Linux):
|
|
|
|
.. code-block::
|
|
|
|
$ rm fib.*.so
|
|
|
|
Using setup.py
|
|
--------------
|
|
|
|
You can also use ``setup.py`` to compile modules using mypyc. Here is an
|
|
example ``setup.py`` file::
|
|
|
|
from setuptools import setup
|
|
|
|
from mypyc.build import mypycify
|
|
|
|
setup(
|
|
name='mylib',
|
|
packages=['mylib'],
|
|
ext_modules=mypycify([
|
|
'mylib/__init__.py',
|
|
'mylib/mod.py',
|
|
]),
|
|
)
|
|
|
|
We used ``mypycify(...)`` to specify which files to compile using
|
|
mypyc. Your ``setup.py`` can include additional Python files outside
|
|
``mypycify(...)`` that won't be compiled.
|
|
|
|
Now you can build a wheel (.whl) file for the package::
|
|
|
|
python3 setup.py bdist_wheel
|
|
|
|
The wheel is created under ``dist/``.
|
|
|
|
You can also compile the C extensions in-place, in the current directory (similar
|
|
to using ``mypyc`` to compile modules)::
|
|
|
|
python3 setup.py build_ext --inplace
|
|
|
|
You can include most `mypy command line options
|
|
<https://mypy.readthedocs.io/en/stable/command_line.html>`_ in the
|
|
list of arguments passed to ``mypycify()``. For example, here we use
|
|
the ``--disallow-untyped-defs`` flag to require that all functions
|
|
have type annotations::
|
|
|
|
...
|
|
setup(
|
|
name='frobnicate',
|
|
packages=['frobnicate'],
|
|
ext_modules=mypycify([
|
|
'--disallow-untyped-defs', # Pass a mypy flag
|
|
'frobnicate.py',
|
|
]),
|
|
)
|
|
|
|
.. note:
|
|
|
|
You may be tempted to use `--check-untyped-defs
|
|
<https://mypy.readthedocs.io/en/stable/command_line.html#cmdoption-mypy-check-untyped-defs>`_
|
|
to type check functions without type annotations. Note that this
|
|
may reduce performance, due to many transitions between type-checked and unchecked
|
|
code.
|
|
|
|
Recommended workflow
|
|
--------------------
|
|
|
|
A simple way to use mypyc is to always compile your code after any
|
|
code changes, but this can get tedious, especially if you have a lot
|
|
of code. Instead, you can do most development in interpreted mode.
|
|
This development workflow has worked smoothly for developing mypy and
|
|
mypyc (often we forget that we aren't working on a vanilla Python
|
|
project):
|
|
|
|
1. During development, use interpreted mode. This gives you a fast
|
|
edit-run cycle.
|
|
|
|
2. Use type annotations liberally and use mypy to type check your code
|
|
during development. Mypy and tests can find most errors that would
|
|
break your compiled code, if you have good type annotation
|
|
coverage. (Running mypy is pretty quick.)
|
|
|
|
3. After you've implemented a feature or a fix, compile your project
|
|
and run tests again, now in compiled mode. Usually nothing will
|
|
break here, assuming your type annotation coverage is good. This
|
|
can happen locally or in a Continuous Integration (CI) job. If you
|
|
have CI, compiling locally may be rarely needed.
|
|
|
|
4. Release or deploy a compiled version. Optionally, include a
|
|
fallback interpreted version for platforms that mypyc doesn't
|
|
support.
|
|
|
|
This mypyc workflow only involves minor tweaks to a typical Python
|
|
workflow. Most of development, testing and debugging happens in
|
|
interpreted mode. Incremental mypy runs, especially when using the
|
|
mypy daemon, are very quick (often a few hundred milliseconds).
|
|
|
|
Next steps
|
|
----------
|
|
|
|
You can sometimes get good results by just annotating your code and
|
|
compiling it. If this isn't providing meaningful performance gains, if
|
|
you have trouble getting your code to work under mypyc, or if you want
|
|
to optimize your code for maximum performance, you should read the
|
|
rest of the documentation in some detail.
|
|
|
|
Here are some specific recommendations, or you can just read the
|
|
documentation in order:
|
|
|
|
* :ref:`using-type-annotations`
|
|
* :ref:`native-classes`
|
|
* :ref:`differences-from-python`
|
|
* :ref:`performance-tips`
|