将默认列表参数传递给数据类

Posted

技术标签:

【中文标题】将默认列表参数传递给数据类【英文标题】:Passing default list argument to dataclasses 【发布时间】:2019-02-03 10:26:19 【问题描述】:

我想在我的班级中传递默认参数, 但不知何故我遇到了问题:

from dataclasses import dataclass, field
from typing import List

@dataclass
class Pizza():
    ingredients: List = field(default_factory=['dow', 'tomatoes'])
    meat: str = field(default='chicken')

    def __repr__(self):
        return 'preparing_following_pizza  '.format(self.ingredients, self.meat)

如果我现在尝试实例化 Pizza,我会收到以下错误:

>>> my_order = Pizza()
Traceback (most recent call last):
  File "pizza.py", line 13, in <module>
    Pizza()
  File "<string>", line 2, in __init__
TypeError: 'list' object is not callable

我做错了什么?

【问题讨论】:

我认为问题可能是因为您还没有创建类的实例 即使创建了类实例,它也不起作用.. 无复制。它与实例完美配合。请发布minimal reproducible example,以便我们查看您做错了什么。 @Aran-Fey 您是否尝试编写代码?正如我所说,它不适用于实例,请参阅我的编辑 我不想使用 init,@dataclass 装饰器的全部意义在于你可以跳过 init 【参考方案1】:

来自the dataclasses.field docs:

field() 的参数为:

default_factory:如果提供,它必须是一个零参数可调用 当该字段需要默认值时将被调用。之中 其他用途,这可用于指定可变字段 默认值,如下所述。两者都指定是错误的 默认和 default_factory。

您的default_factory 不是可调用的 0 参数,而是列表,这就是错误的原因:

from dataclasses import dataclass, field
from typing import List

@dataclass
class Pizza():
    ingredients: List = field(default_factory=['dow', 'tomatoes'])  # <- wrong!

改用 lambda 函数:

@dataclass
class Pizza():
    ingredients: List = field(default_factory=lambda: ['dow', 'tomatoes'])

【讨论】:

我得到undefined variable Listundefined variable field 为了以后参考,需要导入List和field。 from typing import Listfrom dataclasses import field 很好的答案。数据类需要更好的错误信息文档!! :)【参考方案2】:

对于复杂的数据类型,我倾向于这样缩写:

import copy
from dataclasses import dataclass, field
from typing import Dict, Tuple

def default_field(obj):
    return field(default_factory=lambda: copy.copy(obj))

@dataclass
class C:
    complex_attribute: Dict[str, Tuple[int, str]] = default_field("a": (1, "x"), "b": (1, "y"))

【讨论】:

你也应该把它设为copy.copy(obj),否则它将是一个共享的可变对象,这不是一件容易调试的事情。 是的,这真的很糟糕。运行c1 = C(); c2 = C(); print("These are exactly the same object: ", id(c1.complex_attribute) == id(c2.complex_attribute)) 将给出These are exactly the same object: True。请将此更新为使用copy.copy() 感谢 cmets。这是更新,你的意思是什么? 如果字典的值是可变的,则可以使用 copy.deepcopy(obj)。在这种情况下,不是因为它们是元组。

以上是关于将默认列表参数传递给数据类的主要内容,如果未能解决你的问题,请参考以下文章

将参数传递给 UserControl viewmodel

将参数传递给页面,数据不更新

对象作为参数传递给另一个类,通过值还是引用?

将列表作为参数传递给 Python C 模块?

将一个值列表而不是多个参数传递给函数?

Delphi:如何将列表作为参数传递给SQL查询?