Bac*_*ics 43 python python-dataclasses
如何制作数据类的可选属性?
from dataclasses import dataclass
@dataclass
class CampingEquipment:
knife: bool
fork: bool
missing_flask_size: # what to write here?
kennys_stuff = {
'knife': True,
'fork': True
}
print(CampingEquipment(**kennys_stuff))
Run Code Online (Sandbox Code Playgroud)
我尝试过field(init=False),但它给了我:
TypeError: CampingEquipment.__init__() missing 1 required positional argument: 'missing_flask_size'
Run Code Online (Sandbox Code Playgroud)
我所说的“可选”是指__dict__可能包含或不包含“missing_flask_size”键。如果我设置默认值,那么密钥将在那里,但在某些情况下不应该在那里。我想检查它的类型是否存在。
我尝试将 移动field(init=False)到类型位置(冒号之后),这样我就可以更明确地说明我想要的可选内容是键而不是值。
所以我希望这个测试能够通过:
with pytest.raises(AttributeError):
ce = CampingEquipment(**kennys_stuff)
print(ce.missing_flask_size)
Run Code Online (Sandbox Code Playgroud)
Tre*_*ner 59
不可能使用数据类来创建有时存在有时不存在的属性,因为生成的__init__、__eq__、__repr__等对它们检查的属性进行了硬编码。
但是,可以创建一个带有可选参数的数据类,该参数使用属性的默认值(当未提供该属性时)。
from dataclasses import dataclass
from typing import Optional
@dataclass
class CampingEquipment:
knife: bool
fork: bool
missing_flask_size: Optional[int] = None
kennys_stuff = {
'knife':True,
'fork': True
}
print(CampingEquipment(**kennys_stuff))
Run Code Online (Sandbox Code Playgroud)
并且可以使用被接受__init__但不是实际字段的参数来创建数据类。所以你可以这样做:
from dataclasses import dataclass, InitVar
from typing import Optional
@dataclass
class CampingEquipment:
knife: bool
fork: bool
missing_flask_size: InitVar[Optional[int]] = None
def __post_init__(self, missing_flask_size):
if missing_flask_size is not None:
self.missing_flask_size = missing_flask_size
Run Code Online (Sandbox Code Playgroud)
如果您确实希望类要么具有该属性,要么根本不具有该属性,您可以对数据类进行子类化,并创建一个工厂函数,根据该missing_flask_size属性是否存在来创建一个类或另一个类:
from dataclasses import dataclass
@dataclass
class CampingEquipment:
knife: bool
fork: bool
@dataclass
class CampingEquipmentWithFlask:
missing_flask_size: int
def equipment(**fields):
if 'missing_flask_size' in fields:
return CampingEquipmentWithFlask(**fields)
return CampingEquipment(**fields)
kennys_stuff = {
'knife':True,
'fork': True
}
print(CampingEquipment(**kennys_stuff))
Run Code Online (Sandbox Code Playgroud)
如果您真的想要(但我不推荐),您甚至可以自定义 of__new__以在给出CampingEquipment该参数时返回该特殊子类的实例(尽管您还需要在那个班级)。missing_flask_sizeinit=False__init__
use*_*ica 12
对象field应该与 一起使用=,就像默认值一样,而不是:像注释一样。
指定init=False字段意味着调用者根本无法为其传递值。init=False字段应该设置在 中__post_init__,如下所示:
@dataclass
class Example:
a: int
b: int
c: int = field(init=False)
def __post_init__(self):
self.c = self.a + self.b
print(Example(1, 2).c) # prints 3
Run Code Online (Sandbox Code Playgroud)
如果您想让调用者可以选择提供值,则可以设置默认值。如果调用者未提供值,则将使用默认值:
@dataclass
class Example:
a: int
b: int
c: int = -1
print(Example(1, 2).c) # prints -1
print(Example(1, 2, 3).c) # prints 3
Run Code Online (Sandbox Code Playgroud)