关于python:将默认列表参数传递给数据类

Passing default list argument to dataclasses

我想在我的类中传递默认参数,但不知怎么的,我有问题:

1
2
3
4
5
6
7
8
9
10
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,我会得到以下错误:

1
2
3
4
5
6
>>> 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

我做错什么了?


来自dataclasses.field文件:

The parameters to field() are:

  • default_factory: If provided, it must be a zero-argument callable that
    will be called when a default value is needed for this field. Among
    other purposes, this can be used to specify fields with mutable
    default values, as discussed below. It is an error to specify both
    default and default_factory.

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

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

改用lambda函数:

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


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

1
2
3
4
5
6
7
8
9
from dataclasses import dataclass, field
from typing import Dict, Tuple

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

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


此方法不使用typingdataclasses模块,但您可能希望尝试如下操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Pizza():
    defaults = {
        'toppings': ['peppers', 'cheese'],
        'ingredients': ['dough', 'tomato'],
        'meat': 'chicken'
    }
    def __init__(self, toppings=None, meat=None, ingredients=None):
        if toppings is None:
            setattr(self, 'toppings', defaults['toppings'])

         if meat is None:
            setattr(self, 'meat', defaults['meat'])

         if ingredients is None:
            setattr(self, 'ingredients', defaults['ingredients'])

我本可以将__init__中的参数设置为它们的默认值,但我认为这可能会在引用同一列表时引起冲突。