| 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` |