Python 属性库:使用其他属性定义 attr.ib(默认=)

Python attrs library: define attr.ib(default=) using other attributes

我正在使用令人惊叹的 attrs 库以一种非常优雅的方式定义许多对象属性,到目前为止它一直非常有效。

我目前遇到的唯一问题是有时我想通过引用其他 attr.ib() 属性来定义默认值。如果 name 的默认值是静态字符串,下面是一些代码 运行:

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)

问题是 name 没有看到 floatdate,而是 _CountingAttr 对象,因此我得到了 AttributeError (和 TypeError 对应 some_number * 100)。由于我也无法引用 self,我该怎么做?

因此目前使用 default 关键字似乎无法做到这一点。但是,要达到相同的效果,可以使用 __attrs_post_init__ 方法,该方法可用于在实例初始化后执行任意计算: http://attrs.readthedocs.io/en/stable/examples.html?highlight=attrs_post_init#other-goodies

在我的示例中,基本上可以归结为添加

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)

归功于 attrs github 问题跟踪器,它为我指明了正确的方向。

你也可以不用 __attrs_post_init__

只需使用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)