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?

2 Answers

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:

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.

You can also do it without __attrs_post_init__.

Just use default = attr.Factory(lambda self: ..., takes_self=True)

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=attr.Factory(lambda self: "Generic Name {0} - {1}%".format( self.some_date.strftime("%d-%b-%Y"), self.some_number * 100) ), takes_self=True) something_instance = Something(some_date=datetime.date.today(), some_number=0.375) 

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy