I am using the amazing attrs
library to define a lot of object attributes in a very elegant way and it has been working like a charm so far.
The only problem that I am currently having is that I sometimes want to define default values by referencing other attr.ib()
attributes. Here is some code that would run if the default for name
were a static string:
import attr
from attr.validators import instance_of
import datetime
@attr.s
class Something:
some_date = attr.ib(validator=instance_of(datetime.date))
some_number = attr.ib(convert=float)
name = attr.ib(validator=instance_of(str),
default="Generic Name {0} - {1}%".format(
some_date.strftime("%d-%b-%Y"),
some_number * 100)
)
something_instance = Something(some_date=datetime.date.today(), some_number=0.375)
The problem is that name
doesn't see a float
and a date
, but a _CountingAttr
object, hence I get an AttributeError
(and a TypeError
for some_number * 100
). Since I can't reference self
either, how do I do this?
So this seems not possible with the default keyword at the moment. However, to achieve the same effect, it's possible to use the __attrs_post_init__
method, which can used to execute arbitrary calculations after instance initialization: http://attrs.readthedocs.io/en/stable/examples.html?highlight=attrs_post_init#other-goodies
In my example it would basically come down to adding
def __attrs_post_init__(self):
if self.name is None:
self.name = "Generic Name {0} - {1}%".format(
self.some_date.strftime("%d-%b-%Y"),
self.some_number * 100)
Credit goes to the attrs github issue tracker for pointing me in the right direction.