bidict/docs/learning-from-bidict.rst

153 lines
4.7 KiB
ReStructuredText
Raw Normal View History

2018-01-02 20:32:06 +00:00
Learning from bidict
--------------------
Below are some of the more fascinating Python corners
I got to explore further
2018-01-02 20:32:06 +00:00
thanks to working on bidict.
2018-01-02 20:32:06 +00:00
If you are interested in learning more about any of the following,
reading through or even contributing to bidict's code
could be a great way to get started.
2018-01-02 20:32:06 +00:00
.. todo::
2018-01-02 20:32:06 +00:00
The following is just an outline.
Expand and provide more references and examples.
2018-01-02 20:32:06 +00:00
Python's data model
===================
2018-01-02 20:32:06 +00:00
- Making an immutable type hashable,
i.e. insertable into :class:`dict`\s and :class:`set`\s
2018-01-02 20:32:06 +00:00
- See :meth:`object.__hash__` and :meth:`object.__eq__` docs
2018-01-02 20:32:06 +00:00
- How this affects hashable ordered collections
like :class:`~bidict.FrozenOrderedBidict`
that have an order-insensitive
:meth:`~bidict.FrozenOrderedBidict.__eq__`
2018-01-02 20:32:06 +00:00
- All contained items must participate in the hash
2018-01-02 20:32:06 +00:00
- Resulting corner cases produce possibly surprising results:
2018-01-02 20:32:06 +00:00
- See :ref:`nan-as-key`
2018-01-02 20:32:06 +00:00
- See
`pywat#38 <https://github.com/cosmologicon/pywat/issues/38>`_
for some surprising results when keys of different types compare equal,
or when a hashable type's ``__eq__()`` is intransitive
(as in :class:`~collections.OrderedDict`):
2018-01-02 20:32:06 +00:00
- "Intransitive equality was a mistake." Raymond Hettinger
2018-01-02 20:32:06 +00:00
- Thus :ref:`eq-order-insensitive` for :class:`~bidict.FrozenOrderedBidict`
2018-01-02 20:32:06 +00:00
- Using :meth:`object.__new__` to bypass default object initialization,
e.g. for better :meth:`~bidict.bidict.copy` performance
2018-01-02 20:32:06 +00:00
- See `how bidict does this
<https://github.com/jab/bidict/blob/master/bidict/_frozen.py>`_
2018-01-02 20:32:06 +00:00
- Overriding :meth:`object.__getattribute__` for custom attribute lookup
2018-01-02 20:32:06 +00:00
- See :ref:`sorted-bidict-recipes` for example
2018-01-02 20:32:06 +00:00
- Using :meth:`object.__reduce__` to make an object pickleable
that otherwise wouldn't be,
2018-01-02 20:32:06 +00:00
due to e.g. using weakrefs (see below)
Using :mod:`weakref`
====================
- See :ref:`inv-avoids-reference-cycles`
:func:`~collections.namedtuple`-style dynamic class generation
==============================================================
- See `namedbidict's implementation
<https://github.com/jab/bidict/blob/master/bidict/_named.py>`_
2018-01-02 20:32:06 +00:00
How to efficiently implement an ordered mapping
===============================================
- Use a backing dict and doubly-linked list
`like OrderedDict
<https://github.com/python/cpython/blob/a0374d/Lib/collections/__init__.py#L71>`_
- See `OrderedBidict's implementation
<https://github.com/jab/bidict/blob/master/bidict/_ordered.py>`_
API Design
==========
- Integrating with :mod:`collections` via :mod:`collections.abc` and :mod:`abc`
- Extending :class:`collections.abc.Mapping` and :class:`collections.abc.MutableMapping`
- How to make virtual subclasses using
:meth:`abc.ABCMeta.register` or
:meth:`abc.ABCMeta.__subclasshook__` and
:obj:`NotImplemented`.
- Beyond :class:`collections.abc.Mapping`, bidicts implement additional APIs
that :class:`dict` and :class:`~collections.OrderedDict` implement.
- When creating a new API, making it familiar, memorable, and intuitive
is hugely important to a good user experience.
- Making APIs Pythonic
- `Zen of Python <https://www.python.org/dev/peps/pep-0020/>`_
- "Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess."
→ bidict's default duplication policies
- "Explicit is better than implicit.
There should be one—and preferably only one—obvious way to do it."
→ dropped the alternate ``.inv`` APIs that used
the ``~`` operator and the old slice syntax
2018-01-02 20:32:06 +00:00
Portability
===========
- Python 2 vs. Python 3 (mostly :class:`dict` API changes)
2018-01-02 20:32:06 +00:00
- CPython vs. PyPy
- gc / weakref
- http://doc.pypy.org/en/latest/cpython_differences.html#differences-related-to-garbage-collection-strategies
- hence https://github.com/jab/bidict/blob/958ca85/tests/test_hypothesis.py#L168
- nan
2018-01-02 20:32:06 +00:00
Correctness, performance, code quality, etc.
============================================
bidict provided a need to learn these fantastic tools,
many of which have been indispensable
(especially hypothesis see
`bidict's usage <https://github.com/jab/bidict/blob/master/tests/test_hypothesis.py>`_):
2018-01-02 20:32:06 +00:00
- `Pytest <https://docs.pytest.org/en/latest/>`_
- `Coverage <http://coverage.readthedocs.io/en/latest/>`_
- `hypothesis <http://hypothesis.readthedocs.io/en/latest/>`_
- `pytest-benchmark <https://github.com/ionelmc/pytest-benchmark>`_
- `Sphinx <http://www.sphinx-doc.org/en/stable/>`_
- `Travis <https://travis-ci.org/>`_
- `Readthedocs <http://bidict.readthedocs.io/en/latest/>`_
- `Codecov <https://codecov.io>`_
- `lgtm <http://lgtm.com/>`_
- `Pylint <https://www.pylint.org/>`_
- `setuptools_scm <https://github.com/pypa/setuptools_scm>`_