attrs/docs/api.rst

102 lines
3.1 KiB
ReStructuredText

.. _api:
API
===
``characteristic`` consists of class decorators that add attribute-related features to your classes.
.. currentmodule:: characteristic
There are two approaches on how to define those attributes:
#. By defining those attributes as class variables using instances of the :class:`Attribute` class.
This approach has been added as of version 14.0 to make ``characteristic`` future-proof by adding more flexibility.
#. Using a list of names which I henceforth refer to as the 'legacy way'.
As per our backward compatibility policy, support for this approach will *not* be removed before 15.0 (if ever), however no new features will be added so I strongly urge you to *not* use it.
Both approaches usually entail the usage of the :func:`@attributes <attributes>` decorator which will automatically detect the desired approach and prevent mixing of them.
.. autofunction:: attributes
.. autoclass:: Attribute
Legacy
------
There are three that start with ``@with_`` that add *one* feature to your class based on a list of attributes.
Then there's the helper :func:`@attributes <attributes>` that combines them all into one decorator so you don't have to repeat the attribute list multiple times.
.. autofunction:: with_repr
.. doctest::
>>> from characteristic import with_repr
>>> @with_repr(["a", "b"])
... class RClass(object):
... def __init__(self, a, b):
... self.a = a
... self.b = b
>>> c = RClass(42, "abc")
>>> print c
<RClass(a=42, b='abc')>
.. autofunction:: with_cmp
.. doctest::
>>> from characteristic import with_cmp
>>> @with_cmp(["a", "b"])
... class CClass(object):
... def __init__(self, a, b):
... self.a = a
... self.b = b
>>> o1 = CClass(1, "abc")
>>> o2 = CClass(1, "abc")
>>> o1 == o2 # o1.a == o2.a and o1.b == o2.b
True
>>> o1.c = 23
>>> o2.c = 42
>>> o1 == o2 # attributes that are not passed to with_cmp are ignored
True
>>> o3 = CClass(2, "abc")
>>> o1 < o3 # because 1 < 2
True
>>> o4 = CClass(1, "bca")
>>> o1 < o4 # o1.a == o4.a, but o1.b < o4.b
True
.. autofunction:: with_init
.. doctest::
>>> from characteristic import with_init
>>> @with_init(["a", "b"], defaults={"b": 2})
... class IClass(object):
... def __init__(self):
... if self.b != 2:
... raise ValueError("'b' must be 2!")
>>> o1 = IClass(a=1, b=2)
>>> o2 = IClass(a=1)
>>> o1.a == o2.a
True
>>> o1.b == o2.b
True
>>> IClass()
Traceback (most recent call last):
...
ValueError: Missing keyword value for 'a'.
>>> IClass(a=1, b=3) # the custom __init__ is called after the attributes are initialized
Traceback (most recent call last):
...
ValueError: 'b' must be 2!
.. note::
The generated initializer explicitly does *not* support positional
arguments. Those are *always* passed to the existing ``__init__``
unaltered.