1

例如:

@attrs
class Foo:
  a = attrib()

f = Foo(a=1, b=2)

上面的代码会抛出错误,因为类Foo没有battr。但我想丢弃传递b的值,就像我刚刚调用f = Foo(a=1). 在我的用例中,我有动态 dict(我想将其转换为 attr-class),我根本不需要一些键。

4

3 回答 3

1

我想我想出了一个更优雅的解决方案,它允许您利用attrs的功能同时调整__init__逻辑。有关详细信息,请参阅attrs 文档

@attr.s(auto_attribs=True, auto_detect=True)
class Foo():
    a: int
    optional: int = 3

    def __init__(self,**kwargs):
      filtered = {
        attribute.name: kwargs[attribute.name]
        for attribute in self.__attrs_attrs__
        if attribute.name in kwargs
      }
      self.__attrs_init__(**filtered)

上面的代码允许您指定无关的关键字参数。它还允许使用可选参数。

>>> Foo(a = 1, b = 2)
Foo(a=1, optional=3)

attrs检测到显式 init 方法(由于auto_detect=True)并仍然创建 init 函数,但调用它__attrs_init__。这允许您定义自己的 init 函数来进行预处理,然后__attrs_init__在完成后调用。

>>> import inspect
>>> print(inspect.getsource(Foo.__attrs_init__))
def __attrs_init__(self, a, optional=attr_dict['optional'].default):
    self.a = a
    self.optional = optional
于 2021-10-09T20:45:29.453 回答
1
class FromDictMixin:
    @classmethod
    def from_dict(cls, data: dict):
        return cls(**{
            a.name: data[a.name]
            for a in cls.__attrs_attrs__
        })

@attrs
class Foo(FromDictMixin):
    a = attrib()

它有效,但它看起来有点难看。我希望attrslib 有开箱即用的解决方案。

于 2020-01-30T19:45:16.590 回答
0

这似乎更像是一个序列化/反序列化/验证的问题,并且由于多种原因,attrs 对其论点非常严格。其中一个是打字(如类型,而不是按键:)),另一个是健壮性/可调试性。忽略您可能拼错的论点可能会导致非常令人沮丧的时刻。最好将这种东西移到单独的层中。

您可以在https://github.com/python-attrs/attrs/wiki/Extensions-to-attrs中找到一些可能的工具。

于 2020-02-01T05:44:55.060 回答