API¶
characteristic
consists of several class decorators that add features to your classes.
There are four that add one feature each to your class.
And then there’s the helper @attributes
that combines them all into one decorator so you don’t have to repeat the attribute list multiple times.
Generally the decorators take a list of attributes as their first positional argument.
This list can consists of either native strings[*] for simple cases or instances of Attribute
that allow for more customization of characteristic
‘s behavior.
The easiest way to get started is to have a look at the Examples to get a feeling for characteristic
and return later for details!
[*] | Byte strings on Python 2 and Unicode strings on Python 3. |
Note
Every argument except for attrs
for decorators and name
for Attribute
is a keyword argument.
Their positions are coincidental and not guaranteed to remain stable.
-
characteristic.
attributes
(attrs, apply_with_cmp=True, apply_with_init=True, apply_with_repr=True, apply_immutable=False, store_attributes=<function _default_store_attributes>, **kw)¶ A convenience class decorator that allows to selectively apply
with_cmp()
,with_repr()
,with_init()
, andimmutable()
to avoid code duplication.Parameters: - attrs (
list
ofstr
orAttribute
s.) – Attributes to work with. - apply_with_cmp (bool) – Apply
with_cmp()
. - apply_with_init (bool) – Apply
with_init()
. - apply_with_repr (bool) – Apply
with_repr()
. - apply_immutable (bool) – Apply
immutable()
. The only one that is off by default. - store_attributes (callable) – Store the given
attr
s on the class. Should accept two arguments, the class and the attributes, in that order. Note that attributes passed in will always be instances ofAttribute
, (so simple string attributes will already have been converted). By default if unprovided, attributes are stored in acharacteristic_attributes
attribute on the class.
Raises ValueError: If both defaults and an instance of
Attribute
has been passed.New in version 14.0: Added possibility to pass instances of
Attribute
inattrs
.New in version 14.0: Added
apply_*
.New in version 14.2: Added
store_attributes
.Deprecated since version 14.0: Use
Attribute
instead ofdefaults
.Parameters: defaults ( dict
orNone
) – Default values if attributes are omitted on instantiation.Deprecated since version 14.0: Use
apply_with_init
instead ofcreate_init
. Until removal, if either if False,with_init
is not applied.Parameters: create_init (bool) – Apply with_init()
.- attrs (
-
characteristic.
with_repr
(attrs)¶ A class decorator that adds a human readable
__repr__
method to your class using attrs.Parameters: attrs ( list
ofstr
orAttribute
s.) – Attributes to work with.>>> 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')>
-
characteristic.
with_cmp
(attrs)¶ A class decorator that adds comparison methods based on attrs.
For that, each class is treated like a
tuple
of the values of attrs. But only instances of identical classes are compared!Parameters: attrs ( list
ofstr
orAttribute
s.) – Attributes to work with.>>> 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
-
characteristic.
with_init
(attrs, **kw)¶ A class decorator that wraps the
__init__
method of a class and sets attrs using passed keyword arguments before calling the original__init__
.Those keyword arguments that are used, are removed from the kwargs that is passed into your original
__init__
. Optionally, a dictionary of default values for some of attrs can be passed too.Attributes that are defined using
Attribute
and start with underscores will get them stripped for the initializer arguments by default (this behavior is changeable on per-attribute basis when instantiatingAttribute
.Parameters: attrs (
list
ofstr
orAttribute
s.) – Attributes to work with.Raises: - ValueError – If the value for a non-optional attribute hasn’t been passed as a keyword argument.
- ValueError – If both defaults and an instance of
Attribute
has been passed.
Deprecated since version 14.0: Use
Attribute
instead ofdefaults
.Parameters: defaults ( dict
orNone
) – Default values if attributes are omitted on instantiation.>>> from characteristic import with_init, Attribute >>> @with_init(["a", ... Attribute("b", default_factory=lambda: 2), ... Attribute("_c")]) ... class IClass(object): ... def __init__(self): ... if self.b != 2: ... raise ValueError("'b' must be 2!") >>> o1 = IClass(a=1, b=2, c=3) >>> o2 = IClass(a=1, c=3) >>> o1._c 3 >>> 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. Used keyword arguments will not be passed to the original__init__
method and have to be accessed on the class (i.e.self.a
).
-
characteristic.
immutable
(attrs)¶ Class decorator that makes attrs of a class immutable.
That means that attrs can only be set from an initializer. If anyone else tries to set one of them, an
AttributeError
is raised.New in version 14.0.
>>> from characteristic import immutable >>> @immutable([Attribute("foo")]) ... class ImmutableClass(object): ... foo = "bar" >>> ic = ImmutableClass() >>> ic.foo 'bar' >>> ic.foo = "not bar" Traceback (most recent call last): ... AttributeError: Attribute 'foo' of class 'ImmutableClass' is immutable.
Please note, that that doesn’t mean that the attributes themselves are immutable too:
>>> @immutable(["foo"]) ... class C(object): ... foo = [] >>> i = C() >>> i.foo = [42] Traceback (most recent call last): ... AttributeError: Attribute 'foo' of class 'C' is immutable. >>> i.foo.append(42) >>> i.foo [42]
-
class
characteristic.
Attribute
(name, exclude_from_cmp=False, exclude_from_init=False, exclude_from_repr=False, exclude_from_immutable=False, default_value=NOTHING, default_factory=None, instance_of=None, init_aliaser=<function strip_leading_underscores>)¶ A representation of an attribute.
In the simplest case, it only consists of a name but more advanced properties like default values are possible too.
All attributes on the Attribute class are read-only.
Parameters: - name (str) – Name of the attribute.
- exclude_from_cmp (bool) – Ignore attribute in
with_cmp()
. - exclude_from_init (bool) – Ignore attribute in
with_init()
. - exclude_from_repr (bool) – Ignore attribute in
with_repr()
. - exclude_from_immutable (bool) – Ignore attribute in
immutable()
. - default_value –
A value that is used whenever this attribute isn’t passed as an keyword argument to a class that is decorated using
with_init()
(orattributes()
withapply_with_init=True
).Therefore, setting this makes an attribute optional.
Since a default value of None would be ambiguous, a special sentinel
NOTHING
is used. Passing it means the lack of a default value. - default_factory (callable) –
A factory that is used for generating default values whenever this attribute isn’t passed as an keyword argument to a class that is decorated using
with_init()
(orattributes()
withapply_with_init=True
).Therefore, setting this makes an attribute optional.
- instance_of (type) – If used together with
with_init()
(orattributes()
withapply_with_init=True
), the passed value is checked whether it’s an instance of the type passed here. The initializer then raisesTypeError
on mismatch. - init_aliaser (callable) – A callable that is invoked with the name of the
attribute and whose return value is used as the keyword argument name
for the
__init__
created bywith_init()
(orattributes()
withapply_with_init=True
). Usesstrip_leading_underscores()
by default to change_foo
tofoo
. Set toNone
to disable aliasing.
Raises ValueError: If both
default_value
anddefault_factory
have been passed.New in version 14.0.
-
characteristic.
strip_leading_underscores
(attribute_name)¶ Strip leading underscores from attribute_name.
Used by default by the
init_aliaser
argument ofAttribute
.Parameters: attribute_name (str) – The original attribute name to mangle. Return type: str >>> from characteristic import strip_leading_underscores >>> strip_leading_underscores("_foo") 'foo' >>> strip_leading_underscores("__bar") 'bar' >>> strip_leading_underscores("___qux") 'qux'
-
characteristic.
NOTHING
= NOTHING¶ Sentinel class to indicate the lack of a value when
None
is ambiguous.New in version 14.0.