如何使用元组和 dict 解包制作 attrs 类但没有额外的方法

Vin*_* W. 2 python python-attrs python-dataclasses

我刚开始使用attrsPython 模块,它非常漂亮(或者类似地,我们可以使用 Python 3.7 DataClasses)。我有一个常见的使用模式是让类成为参数值的容器。我喜欢分配参数时的标签,以及更清晰的属性样式引用值,但我也喜欢在将值存储在有序 dict 之类的东西中时有几个很好的功能:

  1. *像 atuple或 a一样解包list以输入函数参数
  2. ** 当需要或需要传递关键字时解压缩。

我可以通过在类中添加三个方法来实现这一切

@attr.s
class DataParameters:
    A: float = attr.ib()
    alpha: float = attr.ib()
    c: float = attr.ib()
    k: float = attr.ib()
    M_s: float = attr.ib()

    def keys(self):
        return 'A', 'alpha', 'c', 'k', 'M_s'

    def __getitem__(self, key):
        return getattr(self, key)

    def __iter__(self):
        return (getattr(self, x) for x in self.keys())
Run Code Online (Sandbox Code Playgroud)

然后我可以使用这样的类:

params = DataParameters(1, 2, 3, 4, 5)
result1 = function1(100, 200, *params, 300)
result2 = function2(x=1, y=2, **params)
Run Code Online (Sandbox Code Playgroud)

这里的动机是数据类提供方便和清晰。然而,我不知道我正在编写的模块要求使用数据类是有原因的。希望函数调用应该接受简单的参数,而不是复杂的数据类。

上面的代码很好,但我想知道我是否遗漏了一些可以让我跳过编写函数的东西,因为模式非常清晰。属性按照我希望它们解包的顺序添加,并且可以根据关键字参数的属性名称作为键值对读取。

也许这是这样的:

@addtupleanddictunpacking
@attr.s
class DataParameters:
    A: float = attr.ib()
    alpha: float = attr.ib()
    c: float = attr.ib()
    k: float = attr.ib()
    M_s: float = attr.ib()
Run Code Online (Sandbox Code Playgroud)

但我不确定是否有什么东西attrs可以做到这一点,我还没有找到。另外,我不确定如何在添加属性时保持它们的顺序,并将其转换为 keys 方法。

Sha*_*ger 6

它不直接集成到类,但asdictastuple辅助功能的目的是进行这种转换。

params = DataParameters(1, 2, 3, 4, 5)
result1 = function1(100, 200, *attr.astuple(params), 300)
result2 = function2(x=1, y=2, **attr.asdict(params))
Run Code Online (Sandbox Code Playgroud)

它们没有集成到类本身中,因为这会使类在任何地方都表现为序列或映射,这会导致在需要TypeError/时出现无声的错误行为AttributeError。性能方面,这应该没问题;解包无论如何都会转换为tuple/ dict(它不能直接传递不是 atupledictin 的东西,因为 C API 希望能够在其参数上使用特定于类型的 API)。

如果您真的希望该类充当序列或映射,则基本上必须执行已完成的操作,尽管您可以使用辅助函数来减少自定义代码和重复的变量名称,例如:

@classmethod
def keys(cls):
    return attr.fields_dict(cls).keys()

def __getitem__(self, key):
    return getattr(self, key)

def __iter__(self):
    return iter(attr.astuple(self, recurse=False))  
Run Code Online (Sandbox Code Playgroud)