将默认列表参数传递给数据类
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:
default_factory:如果提供,它必须是一个零参数可调用 当该字段需要默认值时将被调用。之中 其他用途,这可用于指定可变字段 默认值,如下所述。两者都指定是错误的 默认和 default_factory。
field()
的参数为:
您的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 List
和undefined variable field
为了以后参考,需要导入List和field。 from typing import List
from 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)
。在这种情况下,不是因为它们是元组。以上是关于将默认列表参数传递给数据类的主要内容,如果未能解决你的问题,请参考以下文章