dataclassesData Classes数据类

Source code: Lib/dataclasses.py


This module provides a decorator and functions for automatically adding generated special methods such as __init__() and __repr__() to user-defined classes. 该模块提供了一个装饰器和函数,用于自动向用户定义的类添加生成的特殊方法,如__init__()__repr__()It was originally described in PEP 557.最初在PEP 557中进行了描述。

The member variables to use in these generated methods are defined using PEP 526 type annotations. 在这些生成的方法中使用的成员变量是使用PEP 526类型注释定义的。For example, this code:例如,此代码:

from dataclasses import dataclass
@dataclass
class InventoryItem:
"""Class for keeping track of an item in inventory."""
name: str
unit_price: float
quantity_on_hand: int = 0

def total_cost(self) -> float:
return self.unit_price * self.quantity_on_hand

will add, among other things, a __init__() that looks like:将添加一个__init__(),看起来像:

def __init__(self, name: str, unit_price: float, quantity_on_hand: int = 0):
self.name = name
self.unit_price = unit_price
self.quantity_on_hand = quantity_on_hand

Note that this method is automatically added to the class: it is not directly specified in the InventoryItem definition shown above.请注意,此方法将自动添加到类中:它不是在上面显示的InventoryItem定义中直接指定的。

New in version 3.7.版本3.7中新增。

Module contents模块内容

@dataclasses.dataclass(*, init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False, match_args=True, kw_only=False, slots=False)

This function is a decorator that is used to add generated special methods to classes, as described below.此函数是一个装饰器,用于将生成的特殊方法添加到类中,如下所述。

The dataclass() decorator examines the class to find fields. dataclass()修饰符检查类以查找fieldA field is defined as a class variable that has a type annotation. field定义为具有类型注释的类变量。With two exceptions described below, nothing in dataclass() examines the type specified in the variable annotation.除了下面描述的两个例外,dataclass()中没有检查变量注释中指定的类型。

The order of the fields in all of the generated methods is the order in which they appear in the class definition.所有生成的方法中字段的顺序是它们在类定义中出现的顺序。

The dataclass() decorator will add various “dunder” methods to the class, described below. dataclass()装饰器将向类中添加各种“dunder”方法,如下所述。If any of the added methods already exist in the class, the behavior depends on the parameter, as documented below. 如果类中已经存在任何添加的方法,则行为取决于参数,如下所述。The decorator returns the same class that it is called on; no new class is created.装饰器返回其被调用的同一类;不创建新类。

If dataclass() is used just as a simple decorator with no parameters, it acts as if it has the default values documented in this signature. 如果dataclass()只是作为一个没有参数的简单装饰器使用,那么它的行为就好像它具有此签名中记录的默认值一样。That is, these three uses of dataclass() are equivalent:也就是说,dataclass()的这三种用法是等价的:

@dataclass
class C:
...
@dataclass()
class C:
...

@dataclass(init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False, match_args=True, kw_only=False, slots=False)
class C:
...

The parameters to dataclass() are:dataclass()的参数为:

  • init: If true (the default), a __init__() method will be generated.:如果为true(默认值),将生成__init__()方法。

    If the class already defines __init__(), this parameter is ignored.如果类已定义__init__(),则忽略此参数。

  • repr: If true (the default), a __repr__() method will be generated. :如果为true(默认值),将生成__repr__()方法。The generated repr string will have the class name and the name and repr of each field, in the order they are defined in the class. 生成的repr字符串将具有类名以及每个字段的名称和repr,按照它们在类中定义的顺序。Fields that are marked as being excluded from the repr are not included. 不包括标记为从报告中排除的字段。For example:例如: InventoryItem(name='widget', unit_price=3.0, quantity_on_hand=10).

    If the class already defines __repr__(), this parameter is ignored.如果类已定义__repr__(),则忽略此参数。

  • eq: If true (the default), an __eq__() method will be generated. :如果为true(默认值),将生成__eq__()方法。This method compares the class as if it were a tuple of its fields, in order. 该方法按顺序将类作为其字段的元组进行比较。Both instances in the comparison must be of the identical type.比较中的两个实例必须是相同的类型。

    If the class already defines __eq__(), this parameter is ignored.如果类已定义__eq__(),则忽略此参数。

  • order: If true (the default is False), __lt__(), __le__(), __gt__(), and __ge__() methods will be generated. :如果为true(默认值为False),将生成__lt__()__le__()__gt__()__ge__()方法。These compare the class as if it were a tuple of its fields, in order. 它们将类作为其字段的元组,按顺序进行比较。Both instances in the comparison must be of the identical type. 比较中的两个实例必须是相同的类型。If order is true and eq is false, a ValueError is raised.如果ordertrueeqfalse,则会引发ValueError

    If the class already defines any of __lt__(), __le__(), __gt__(), or __ge__(), then TypeError is raised.如果该类已经定义了__lt__()__le__()__gt__()__ge__(),则会引发TypeError

  • unsafe_hash: If False (the default), a __hash__() method is generated according to how eq and frozen are set.:如果为False(默认值),将根据eqfrozen的设置生成__hash__()方法。

    __hash__() is used by built-in hash(), and when objects are added to hashed collections such as dictionaries and sets. __hash__()由内置的hash()使用,当对象被添加到哈希集合(如字典和集合)中时。Having a __hash__() implies that instances of the class are immutable. 拥有__hash__()意味着类的实例是不可变的。Mutability is a complicated property that depends on the programmer’s intent, the existence and behavior of __eq__(), and the values of the eq and frozen flags in the dataclass() decorator.可变性是一个复杂的属性,它取决于程序员的意图、__eq__()的存在和行为,以及dataclass()修饰符中eqfrozen标志的值。

    By default, dataclass() will not implicitly add a __hash__() method unless it is safe to do so. 默认情况下,dataclass()不会隐式添加__hash__()方法,除非这样做是安全的。Neither will it add or change an existing explicitly defined __hash__() method. 它也不会添加或更改现有的显式定义的__hash__()方法。Setting the class attribute __hash__ = None has a specific meaning to Python, as described in the __hash__() documentation.设置类属性__hash__=None对Python有特定意义,如__hash__()文档中所述。

    If __hash__() is not explicitly defined, or if it is set to None, then dataclass() may add an implicit __hash__() method. 如果__hash__()未显式定义,或者设置为None,则dataclass()可以添加隐式__hash__()方法。Although not recommended, you can force dataclass() to create a __hash__() method with unsafe_hash=True. 虽然不建议使用,但可以强制dataclass()创建一个__hash__()方法,其中unsafe_hash=TrueThis might be the case if your class is logically immutable but can nonetheless be mutated. 如果您的类在逻辑上是不可变的,但仍然可以进行变异,则可能会出现这种情况。This is a specialized use case and should be considered carefully.这是一个专门的用例,应该仔细考虑。

    Here are the rules governing implicit creation of a __hash__() method. 以下是控制__hash__()方法隐式创建的规则。Note that you cannot both have an explicit __hash__() method in your dataclass and set unsafe_hash=True; this will result in a TypeError.请注意,不能在数据类中同时使用显式__hash__()方法并设置unsafe_hash=True;这将导致TypeError

    If eq and frozen are both true, by default dataclass() will generate a __hash__() method for you. 如果eqfreeze都为dataclass(),默认情况下dataclass()将为您生成__hash__()方法。If eq is true and frozen is false, __hash__() will be set to None, marking it unhashable (which it is, since it is mutable). 如果eqtrue,而frozenfalse__hash__()将设置为None,将其标记为不可更改(因为它是可变的)。If eq is false, __hash__() will be left untouched meaning the __hash__() method of the superclass will be used (if the superclass is object, this means it will fall back to id-based hashing).如果eqfalse__hash__()将保持不变,这意味着将使用超类的__hash__()方法(如果超类是object,则意味着它将返回到基于id的哈希)。

  • frozen: If true (the default is False), assigning to fields will generate an exception. :如果为true(默认为False),则分配给字段将生成异常。This emulates read-only frozen instances. 这将模拟只读冻结实例。If __setattr__() or __delattr__() is defined in the class, then TypeError is raised. 如果在类中定义了__setattr__()__delatt__(),则引发TypeErrorSee the discussion below.请参阅下面的讨论。

  • match_args: If true (the default is True), the __match_args__ tuple will be created from the list of parameters to the generated __init__() method (even if __init__() is not generated, see above). :如果为true(默认值为true),__match_args__元组将从参数列表创建到生成的__init__()方法(即使未生成__init__()),请参阅上文)。If false, or if __match_args__ is already defined in the class, then __match_args__ will not be generated.如果为false,或者类中已经定义了__match_args__,则不会生成__match_args__

New in version 3.10.版本3.10中新增。

  • kw_only: If true (the default value is False), then all fields will be marked as keyword-only. :如果为true(默认值为False),则所有字段都将标记为仅关键字。If a field is marked as keyword-only, then the only affect is that the __init__() parameter generated from a keyword-only field must be specified with a keyword when __init__() is called. 如果字段被标记为仅关键字,则唯一的影响是,在调用__init__()时,从仅关键字字段生成的__init__()参数必须用关键字指定。There is no effect on any other aspect of dataclasses. 对数据类的任何其他方面都没有影响。See the parameter glossary entry for details. 有关详细信息,请参阅参数词汇表条目。Also see the KW_ONLY section.另请参见KW_ONLY部分。

New in version 3.10.版本3.10中新增。

  • slots: If true (the default is False), __slots__ attribute will be generated and new class will be returned instead of the original one. :如果为true(默认为False),将生成__slots__属性,并返回新类而不是原始类。If __slots__ is already defined in the class, then TypeError is raised.如果类中已定义__slots__,则会引发TypeError

New in version 3.10.版本3.10中新增。

fields may optionally specify a default value, using normal Python syntax:可以使用常规Python语法指定默认值:

@dataclass
class C:
a: int # 'a' has no default value
b: int = 0 # assign a default value for 'b'

In this example, both a and b will be included in the added __init__() method, which will be defined as:在本例中,ab都将包含在添加的__init__()方法中,该方法将定义为:

def __init__(self, a: int, b: int = 0):

TypeError will be raised if a field without a default value follows a field with a default value. 如果没有默认值的字段跟在具有默认值的域之后,将引发。This is true whether this occurs in a single class, or as a result of class inheritance.无论这发生在单个类中,还是作为类继承的结果,都是如此。

dataclasses.field(*, default=MISSING, default_factory=MISSING, init=True, repr=True, hash=None, compare=True, metadata=None, kw_only=MISSING)

For common and simple use cases, no other functionality is required. 对于常见和简单的用例,不需要其他功能。There are, however, some dataclass features that require additional per-field information. 但是,有些数据类功能需要额外的每个字段信息。To satisfy this need for additional information, you can replace the default field value with a call to the provided field() function. 为了满足对附加信息的需求,您可以通过调用提供的field()函数来替换默认字段值。For example:例如:

@dataclass
class C:
mylist: list[int] = field(default_factory=list)
c = C()
c.mylist += [1, 2, 3]

As shown above, the MISSING value is a sentinel object used to detect if some parameters are provided by the user. 如上所示,MISSING值是一个哨兵对象,用于检测用户是否提供了某些参数。This sentinel is used because None is a valid value for some parameters with a distinct meaning. 之所以使用此sentinel,是因为None对于某些具有不同含义的参数是有效值。No code should directly use the MISSING value.任何代码都不应直接使用MISSING值。

The parameters to field() are:field()的参数如下:

  • default: If provided, this will be the default value for this field. :如果提供,这将是此字段的默认值。This is needed because the field() call itself replaces the normal position of the default value.这是必需的,因为field()调用本身会替换默认值的正常位置。

  • 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.同时指定defaultdefault_factory是错误的。

  • init: If true (the default), this field is included as a parameter to the generated __init__() method.:如果为true(默认值),则此字段作为生成的__init__()方法的参数包含。

  • repr: If true (the default), this field is included in the string returned by the generated __repr__() method.:如果为true(默认值),则此字段包含在生成的__repr_()方法返回的字符串中。

  • hash: This can be a bool or None. :这可以是bool或NoneIf true, this field is included in the generated __hash__() method. 如果为true,则此字段包含在生成的__hash__()方法中。If None (the default), use the value of compare: this would normally be the expected behavior. 如果None(默认值),则使用compare的值:这通常是预期的行为。A field should be considered in the hash if it’s used for comparisons. 如果用于比较,则应在哈希中考虑字段。Setting this value to anything other than None is discouraged.不建议将此值设置为None以外的任何值。

    One possible reason to set hash=False but compare=True would be if a field is expensive to compute a hash value for, that field is needed for equality testing, and there are other fields that contribute to the type’s hash value. 设置hash=Falsecompare=True的一个可能原因是,如果一个字段计算哈希值的成本很高,该字段需要进行相等测试,并且还有其他字段对该类型的哈希值有贡献。Even if a field is excluded from the hash, it will still be used for comparisons.即使字段从哈希中排除,它仍将用于比较。

  • compare: If true (the default), this field is included in the generated equality and comparison methods (__eq__(), __gt__(), et al.).:如果为true(默认值),则此字段包含在生成的相等和比较方法(__eq__()__gt__()等)中。

  • metadata: This can be a mapping or None. None is treated as an empty dict. :这可以是映射或无。没有一个被视为空字典。This value is wrapped in MappingProxyType() to make it read-only, and exposed on the Field object. 该值被包装在MappingProxyType()中以使其只读,并在Field对象上公开。It is not used at all by Data Classes, and is provided as a third-party extension mechanism. 数据类根本不使用它,而是作为第三方扩展机制提供的。Multiple third-parties can each have their own key, to use as a namespace in the metadata.多个第三方可以各自拥有自己的密钥,用作元数据中的命名空间。

  • kw_only: If true, this field will be marked as keyword-only. :如果为true,则此字段将仅标记为关键字。This is used when the generated __init__() method’s parameters are computed.这在计算生成的__init__()方法的参数时使用。

New in version 3.10.版本3.10中新增。

If the default value of a field is specified by a call to field(), then the class attribute for this field will be replaced by the specified default value. 如果通过调用field()指定字段的默认值,则该字段的class属性将被指定的default值替换。If no default is provided, then the class attribute will be deleted. 如果未提供default,则将删除class属性。The intent is that after the dataclass() decorator runs, the class attributes will all contain the default values for the fields, just as if the default value itself were specified. 其目的是在dataclass()装饰器运行后,类属性将全部包含字段的默认值,就像指定了默认值一样。For example, after:例如,在:

@dataclass
class C:
x: int
y: int = field(repr=False)
z: int = field(repr=False, default=10)
t: int = 20

The class attribute C.z will be 10, the class attribute C.t will be 20, and the class attributes C.x and C.y will not be set.类属性C.z将为10,类属性C.t将为20,并且不设置类属性C.xC.y

classdataclasses.Field

Field objects describe each defined field. 对象描述每个定义的字段。These objects are created internally, and are returned by the fields() module-level method (see below). 这些对象是在内部创建的,并由fields()模块级方法返回(见下文)。Users should never instantiate a Field object directly. 用户不应直接实例化Field对象。Its documented attributes are:其记录属性包括:

  • name: The name of the field.:字段的名称。

  • type: The type of the field.:字段的类型。

  • default, default_factory, init, repr, hash, compare, metadata, and kw_only have the identical meaning and values as they do in the field() function.defaultdefault_factoryinitreprhashcomparemetadatakw_only具有与field()函数中相同的含义和值。

Other attributes may exist, but they are private and must not be inspected or relied on.其他属性可能存在,但它们是私有的,不得检查或依赖。

dataclasses.fields(class_or_instance)

Returns a tuple of Field objects that define the fields for this dataclass. 返回定义此数据类的字段的Field对象的元组。Accepts either a dataclass, or an instance of a dataclass. 接受数据类或数据类的实例。Raises TypeError if not passed a dataclass or instance of one. 如果未传递数据类或数据类的实例,则引发TypeErrorDoes not return pseudo-fields which are ClassVar or InitVar.不返回ClassVarInitVar的伪字段。

dataclasses.asdict(obj, *, dict_factory=dict)

Converts the dataclass obj to a dict (by using the factory function dict_factory). 将数据类obj转换为dict(通过使用工厂函数dict_factory)。Each dataclass is converted to a dict of its fields, as name: value pairs. 每个数据类都转换为其字段的dict,如name: value对。dataclasses, dicts, lists, and tuples are recursed into. 数据类、字典、列表和元组被递归到。Other objects are copied with copy.deepcopy().使用copy.deepcopy()复制其他对象。

Example of using asdict() on nested dataclasses:在嵌套数据类上使用asdict()的示例:

@dataclass
class Point:
x: int
y: int
@dataclass
class C:
mylist: list[Point]

p = Point(10, 20)
assert asdict(p) == {'x': 10, 'y': 20}

c = C([Point(0, 0), Point(10, 4)])
assert asdict(c) == {'mylist': [{'x': 0, 'y': 0}, {'x': 10, 'y': 4}]}

To create a shallow copy, the following workaround may be used:要创建浅层副本,可以使用以下解决方法:

dict((field.name, getattr(obj, field.name)) for field in fields(obj))

asdict() raises TypeError if obj is not a dataclass instance.如果obj不是数据类实例,asdict()将引发TypeError

dataclasses.astuple(obj, *, tuple_factory=tuple)

Converts the dataclass obj to a tuple (by using the factory function tuple_factory). 将数据类obj转换为元组(通过使用工厂函数tuple_factory)。Each dataclass is converted to a tuple of its field values. dataclasses, dicts, lists, and tuples are recursed into. 每个数据类都转换为其字段值的元组。数据类、字典、列表和元组被递归到。Other objects are copied with copy.deepcopy().使用copydeepcopy()复制其他对象。

Continuing from the previous example:继续上一示例:

assert astuple(p) == (10, 20)
assert astuple(c) == ([(0, 0), (10, 4)],)

To create a shallow copy, the following workaround may be used:要创建浅层副本,可以使用以下解决方法:

tuple(getattr(obj, field.name) for field in dataclasses.fields(obj))

astuple() raises TypeError if obj is not a dataclass instance.如果obj不是数据类实例,astuple()将引发TypeError

dataclasses.make_dataclass(cls_name, fields, *, bases=(), namespace=None, init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False, match_args=True, kw_only=False, slots=False)

Creates a new dataclass with name cls_name, fields as defined in fields, base classes as given in bases, and initialized with a namespace as given in namespace. 创建一个名为cls_namefields中定义的字段、bases中给定的基类,并用命名空间中给定的namespace初始化。fields is an iterable whose elements are each either name, (name, type), or (name, type, Field). fields是一个可迭代的元素,其元素分别为name(name, type)(name, type, Field)If just name is supplied, typing.Any is used for type. 如果只提供name,则typing.Any用于typeThe values of init, repr, eq, order, unsafe_hash, frozen, match_args, kw_only, and slots have the same meaning as they do in dataclass().initrepreqorderunsafehashfreezematch_argskw_onlyslots的值与dataclass()中的值具有相同的含义。

This function is not strictly required, because any Python mechanism for creating a new class with __annotations__ can then apply the dataclass() function to convert that class to a dataclass. 这个函数并不是严格要求的,因为任何Python机制都可以使用__annotations__创建新类,然后可以应用dataclass()函数将该类转换为数据类。This function is provided as a convenience. 提供此功能是为了方便。For example:例如:

C = make_dataclass('C',
[('x', int),
'y',
('z', int, field(default=5))],
namespace={'add_one': lambda self: self.x + 1})

Is equivalent to:相当于:

@dataclass
class C:
x: int
y: 'typing.Any'
z: int = 5
def add_one(self):
return self.x + 1
dataclasses.replace(obj, /, **changes)

Creates a new object of the same type as obj, replacing fields with values from changes. 创建一个与obj类型相同的新对象,用changes后的值替换字段。If obj is not a Data Class, raises TypeError. 如果obj不是数据类,则引发TypeErrorIf values in changes do not specify fields, raises TypeError.如果changes中的值未指定字段,则引发TypeError

The newly returned object is created by calling the __init__() method of the dataclass. 新返回的对象是通过调用数据类的__init__()方法创建的。This ensures that __post_init__(), if present, is also called.这确保__post_init__()(如果存在)也被调用。

Init-only variables without default values, if any exist, must be specified on the call to replace() so that they can be passed to __init__() and __post_init__().只有Init没有默认值的变量(如果存在)必须在对replace()的调用中指定,以便将它们传递给__Init__()__post_Init__()

It is an error for changes to contain any fields that are defined as having init=False. 如果changes包含定义为具有init=False的任何字段,则是错误的。A ValueError will be raised in this case.在这种情况下,将引发ValueError

Be forewarned about how init=False fields work during a call to replace(). 在调用replace()时,请预先警告init=False字段是如何工作的。They are not copied from the source object, but rather are initialized in __post_init__(), if they’re initialized at all. 它们不是从源对象复制的,而是在__post_init__()中初始化的(如果它们已经初始化)。It is expected that init=False fields will be rarely and judiciously used. 预计init=False字段将很少且明智地使用。If they are used, it might be wise to have alternate class constructors, or perhaps a custom replace() (or similarly named) method which handles instance copying.如果使用了它们,最好使用替代类构造函数,或者使用一个处理实例复制的自定义replace()(或类似名称)方法。

dataclasses.is_dataclass(obj)

Return True if its parameter is a dataclass or an instance of one, otherwise return False.如果其参数是dataclass或dataclass的实例,则返回True,否则返回False

If you need to know if a class is an instance of a dataclass (and not a dataclass itself), then add a further check for not isinstance(obj, type):如果您需要知道某个类是否是dataclass的实例(而不是dataclass本身),则需要进一步检查not isinstance(obj, type)

def is_dataclass_instance(obj):
return is_dataclass(obj) and not isinstance(obj, type)
dataclasses.MISSING

A sentinel value signifying a missing default or default_factory.表示缺少默认值或default_factory的前哨值。

dataclasses.KW_ONLY

A sentinel value used as a type annotation. 用作类型注释的哨兵值。Any fields after a pseudo-field with the type of KW_ONLY are marked as keyword-only fields. 类型为KW_ONLY的伪字段之后的任何字段都标记为仅关键字字段。Note that a pseudo-field of type KW_ONLY is otherwise completely ignored. 请注意,否则将完全忽略KW_ONLY类型的伪字段。This includes the name of such a field. 这包括此类字段的名称。By convention, a name of _ is used for a KW_ONLY field. 按照惯例,名称_用于KW_ONLY字段。Keyword-only fields signify __init__() parameters that must be specified as keywords when the class is instantiated.仅关键字字段表示__init__()参数,这些参数在实例化类时必须指定为关键字。

In this example, the fields y and z will be marked as keyword-only fields:在本例中,字段yz将标记为仅关键字字段:

@dataclass
class Point:
x: float
_: KW_ONLY
y: float
z: float
p = Point(0, y=1.5, z=2.0)

In a single dataclass, it is an error to specify more than one field whose type is KW_ONLY.在单个数据类中,指定多个类型为KW_ONLY的字段是错误的。

New in version 3.10.版本3.10中新增。

exceptiondataclasses.FrozenInstanceError

Raised when an implicitly defined __setattr__() or __delattr__() is called on a dataclass which was defined with frozen=True. 当对定义为frozen=True的数据类调用隐式定义的__setattr__()__delatt__()时引发。It is a subclass of AttributeError.它是AttributeError的子类。

Post-init processing初始化后处理

The generated __init__() code will call a method named __post_init__(), if __post_init__() is defined on the class. 如果在类上定义了__post_init__(),则生成的__init__()代码将调用名为__post_init__()的方法。It will normally be called as self.__post_init__(). 它通常被称为self.__post_init__()However, if any InitVar fields are defined, they will also be passed to __post_init__() in the order they were defined in the class. 但是,如果定义了任何InitVar字段,它们也将按照在类中定义的顺序传递给__post_init__()If no __init__() method is generated, then __post_init__() will not automatically be called.如果未生成__init__()方法,则不会自动调用__post_init__()

Among other uses, this allows for initializing field values that depend on one or more other fields. 在其他用途中,这允许初始化依赖于一个或多个其他字段的字段值。For example:例如:

@dataclass
class C:
a: float
b: float
c: float = field(init=False)
def __post_init__(self):
self.c = self.a + self.b

The __init__() method generated by dataclass() does not call base class __init__() methods. dataclass()生成的__init__()方法不调用基类__init__()方法。If the base class has an __init__() method that has to be called, it is common to call this method in a __post_init__() method:如果基类具有必须调用的__init__()方法,则通常在__post_init__()中调用此方法:

@dataclass
class Rectangle:
height: float
width: float
@dataclass
class Square(Rectangle):
side: float

def __post_init__(self):
super().__init__(self.side, self.side)

Note, however, that in general the dataclass-generated __init__() methods don’t need to be called, since the derived dataclass will take care of initializing all fields of any base class that is a dataclass itself.然而,请注意,通常不需要调用数据类生成的__init__()方法,因为派生的数据类将负责初始化任何基类的所有字段,而基类本身就是一个数据类。

See the section below on init-only variables for ways to pass parameters to __post_init__(). 有关将参数传递给__post_init__()的方法,请参阅下面关于仅初始化变量的部分。Also see the warning about how replace() handles init=False fields.另请参见有关replace()如何处理init=False字段的警告。

Class variables类变量

One of two places where dataclass() actually inspects the type of a field is to determine if a field is a class variable as defined in PEP 526. dataclass()实际检查字段类型的两个地方之一是确定字段是否是PEP 526中定义的类变量。It does this by checking if the type of the field is typing.ClassVar. 它通过检查字段的类型是否为typing.ClassVar来完成此操作。If a field is a ClassVar, it is excluded from consideration as a field and is ignored by the dataclass mechanisms. 如果某个字段是ClassVar,则将其作为字段排除在外,并被数据类机制忽略。Such ClassVar pseudo-fields are not returned by the module-level fields() function.模块级fields()函数不会返回此类ClassVar伪字段。

Init-only variables仅初始化变量

The other place where dataclass() inspects a type annotation is to determine if a field is an init-only variable. dataclass()检查类型注释的另一个地方是确定字段是否是仅初始化的变量。It does this by seeing if the type of a field is of type dataclasses.InitVar. 它通过查看字段的类型是否为dataclasses.InitVar类型来执行此操作。If a field is an InitVar, it is considered a pseudo-field called an init-only field. 如果一个字段是InitVar,则它被认为是一个伪字段,称为仅初始化字段。As it is not a true field, it is not returned by the module-level fields() function. 由于它不是真字段,因此模块级fields()函数不会返回它。Init-only fields are added as parameters to the generated __init__() method, and are passed to the optional __post_init__() method. They are not otherwise used by dataclasses.仅初始化字段作为参数添加到生成的__Init__()方法中,并传递给可选的__post_Init__()。数据类不使用它们。

For example, suppose a field will be initialized from a database, if a value is not provided when creating the class:例如,如果创建类时未提供值,则假设将从数据库初始化字段:

@dataclass
class C:
i: int
j: int = None
database: InitVar[DatabaseType] = None
def __post_init__(self, database):
if self.j is None and database is not None:
self.j = database.lookup('j')

c = C(10, database=my_database)

In this case, fields() will return Field objects for i and j, but not for database.在这种情况下,fields()将返回ijField对象,但不返回数据库的Field对象。

Frozen instances冻结实例

It is not possible to create truly immutable Python objects. 创建真正不可变的Python对象是不可能的。However, by passing frozen=True to the dataclass() decorator you can emulate immutability. 然而,通过向dataclass()修饰符传递frozen=True,可以模拟不变性。In that case, dataclasses will add __setattr__() and __delattr__() methods to the class. 在这种情况下,数据类将向类中添加__setattr__()__delatt__()方法。These methods will raise a FrozenInstanceError when invoked.这些方法在调用时将引发FrozenInstanceError

There is a tiny performance penalty when using frozen=True: __init__() cannot use simple assignment to initialize fields, and must use object.__setattr__().使用frozen=True时会有一点性能损失:__init__()不能使用简单赋值来初始化字段,必须使用对象object.__setattr__()

Inheritance继承

When the dataclass is being created by the dataclass() decorator, it looks through all of the class’s base classes in reverse MRO (that is, starting at object) and, for each dataclass that it finds, adds the fields from that base class to an ordered mapping of fields. dataclass()修饰符创建数据类时,它会反向MRO(即从object开始)查看该类的所有基类,并为找到的每个数据类将该基类中的字段添加到字段的有序映射中。After all of the base class fields are added, it adds its own fields to the ordered mapping. 添加所有基类字段后,它将自己的字段添加到有序映射中。All of the generated methods will use this combined, calculated ordered mapping of fields. 所有生成的方法都将使用这种组合的、计算出的字段有序映射。Because the fields are in insertion order, derived classes override base classes. 因为字段是按插入顺序排列的,所以派生类重写基类。An example:例如:

@dataclass
class Base:
x: Any = 15.0
y: int = 0
@dataclass
class C(Base):
z: int = 10
x: int = 15

The final list of fields is, in order, x, y, z. 字段的最终列表依次为xyzThe final type of x is int, as specified in class C.x的最终类型是int,如C类中所指定的。

The generated __init__() method for C will look like:C生成的__init__()方法如下所示:

def __init__(self, x: int = 15, y: int = 0, z: int = 10):

Re-ordering of keyword-only parameters in __init__()__init__()中仅关键字参数的重新排序

After the parameters needed for __init__() are computed, any keyword-only parameters are moved to come after all regular (non-keyword-only) parameters. 在计算__init__()所需的参数后,任何仅关键字的参数都会移动到所有常规(非仅关键字)参数之后。This is a requirement of how keyword-only parameters are implemented in Python: they must come after non-keyword-only parameters.这是Python中如何实现仅关键字参数的一个要求:它们必须在非仅关键字参数之后。

In this example, Base.y, Base.w, and D.t are keyword-only fields, and Base.x and D.z are regular fields:在此示例中,Base.yBase.wD.t是仅关键字字段,Base.xD.z是常规字段:

@dataclass
class Base:
x: Any = 15.0
_: KW_ONLY
y: int = 0
w: int = 1
@dataclass
class D(Base):
z: int = 10
t: int = field(kw_only=True, default=0)

The generated __init__() method for D will look like:D生成的__init__()方法如下所示:

def __init__(self, x: Any = 15.0, z: int = 10, *, y: int = 0, w: int = 1, t: int = 0):

Note that the parameters have been re-ordered from how they appear in the list of fields: parameters derived from regular fields are followed by parameters derived from keyword-only fields.请注意,参数已根据它们在字段列表中的显示方式进行了重新排序:从常规字段派生的参数后跟从仅关键字字段派生的。

The relative ordering of keyword-only parameters is maintained in the re-ordered __init__() parameter list.仅关键字参数的相对排序在重新排序的__init__()参数列表中保持。

Default factory functions默认工厂功能

If a field() specifies a default_factory, it is called with zero arguments when a default value for the field is needed. 如果field()指定了default_factory,则当需要字段的默认值时,将使用零参数调用它。For example, to create a new instance of a list, use:例如,要创建列表的新实例,请使用:

mylist: list = field(default_factory=list)

If a field is excluded from __init__() (using init=False) and the field also specifies default_factory, then the default factory function will always be called from the generated __init__() function. 如果从__init__()中排除了一个字段(使用init=False),并且该字段还指定了default_factory,那么将始终从生成的__init__()函数中调用默认工厂函数。This happens because there is no other way to give the field an initial value.之所以发生这种情况,是因为没有其他方法可以为字段赋予初始值。

Mutable default values可变默认值

Python stores default member variable values in class attributes. Python将默认成员变量值存储在类属性中。Consider this example, not using dataclasses:考虑这个例子,不使用数据类:

class C:
x = []
def add(self, element):
self.x.append(element)
o1 = C()
o2 = C()
o1.add(1)
o2.add(2)
assert o1.x == [1, 2]
assert o1.x is o2.x

Note that the two instances of class C share the same class variable x, as expected.注意,C类的两个实例共享相同的类变量x,正如预期的那样。

Using dataclasses, if this code was valid:使用数据类,如果此代码有效:

@dataclass
class D:
x: List = []
def add(self, element):
self.x += element

it would generate code similar to:它将生成类似于以下内容的代码:

class D:
x = []
def __init__(self, x=x):
self.x = x
def add(self, element):
self.x += element
assert D().x is D().x

This has the same issue as the original example using class C. 这与使用C类的原始示例有相同的问题。That is, two instances of class D that do not specify a value for x when creating a class instance will share the same copy of x. 也就是说,在创建类实例时未指定x值的两个D类实例将共享x的相同副本。Because dataclasses just use normal Python class creation they also share this behavior. 因为数据类只是使用普通的Python类创建,所以它们也共享这种行为。There is no general way for Data Classes to detect this condition. 数据类没有检测这种情况的通用方法。Instead, the dataclass() decorator will raise a TypeError if it detects a default parameter of type list, dict, or set. 相反,如果dataclass()装饰器检测到类型listdictset的默认参数,它将引发TypeErrorThis is a partial solution, but it does protect against many common errors.这是一个部分解决方案,但它确实可以防止许多常见错误。

Using default factory functions is a way to create new instances of mutable types as default values for fields:使用默认工厂函数是创建可变类型的新实例作为字段的默认值的一种方法:

@dataclass
class D:
x: list = field(default_factory=list)
assert D().x is not D().x