将辅助变量传递给数据类 __init__ 而不分配它们
Passing helper variables to dataclass __init__ without assigning them
我有一个根级别 config
class,我通过依赖注入在我的代码库中传递它。
问题是,我有这个数据class需要这个配置中的一些属性来计算__post_init__()
中的值world_coords
。
为了保持我的测试干净并规避其他测试导入问题(此处未讨论),我希望能够将配置直接传递给该对象,而不是从导入中读取这些值。但是,如果我将配置结构化为一个参数,它就会成为数据 class 的一个属性,这是我试图避免的。 RoadSegmentNode
确实不需要在使用后保留对配置的引用。
这是class的基本结构:
@dataclass(eq=True, frozen=True) # make hashable
class RoadSegmentNode:
tile_index: Tuple[int, int] # (r, c)
dir: Direction
node_type: RoadNodeType
world_coords: Tuple[int, int] = field(init=False)
def __post_init__(self):
# (Use config variables here, e.g. `config.TILE_WIDTH`, to calculate x and y)
# Hack to get around frozen=True. We don't care that we're mutating
# an "immutable" object on __init__().
object.__setattr__(self, "world_coords", (x, y))
这是我暂时使用依赖注入模型来解锁测试的权宜之计。请注意 RoadSegmentNode
现在如何拥有一堆仅用于初始化的新属性。这比保留对配置的引用要好一点,因为至少它们是明确的,但它仍然是一个非常糟糕的设计。
@dataclass(eq=True, frozen=True) # make hashable
class RoadSegmentNode:
# NOTE: DO NOT ACCESS THESE ATTRIBUTES!
grid_width: int
grid_height: int
tile_width: int
tile_height: int
road_width: int
tile_index: Tuple[int, int] # (r, c)
dir: Direction
node_type: RoadNodeType
world_coords: Tuple[int, int] = field(init=False)
def __post_init__(self):
# (Use attributes here, e.g. `self.tile_width`, to calculate x and y)
# Hack to get around frozen=True. We don't care that we're mutating
# an "immutable" object on __init__().
object.__setattr__(self, "world_coords", (x, y))
如何将配置传递给数据class进行初始化而不使其成为数据class的属性?我什至应该考虑为这个用例使用 dataclass 吗?我相信初衷是保持所有实例不可变,但我无法确认。
您应该将 config
定义为 init-only variable。这样它将传递给 __post_init__()
,但之后会消失:
from dataclass import dataclass, field
from typing import InitVar
@dataclass(eq=True, frozen=True)
class RoadSegmentNode:
tile_index: Tuple[int, int]
dir: Direction
node_type: RoadNodeType
world_coords: Tuple[int, int] = field(init=False)
config: InitVar[Config] # will not appear in instances
def __post_init__(self, config):
x, y = ..., ... # calculate using config
# looks hacky for sure, but is the right way to work with frozen dataclasses
object.__setattr__(self, "world_coords", (x, y))
我有一个根级别 config
class,我通过依赖注入在我的代码库中传递它。
问题是,我有这个数据class需要这个配置中的一些属性来计算__post_init__()
中的值world_coords
。
为了保持我的测试干净并规避其他测试导入问题(此处未讨论),我希望能够将配置直接传递给该对象,而不是从导入中读取这些值。但是,如果我将配置结构化为一个参数,它就会成为数据 class 的一个属性,这是我试图避免的。 RoadSegmentNode
确实不需要在使用后保留对配置的引用。
这是class的基本结构:
@dataclass(eq=True, frozen=True) # make hashable
class RoadSegmentNode:
tile_index: Tuple[int, int] # (r, c)
dir: Direction
node_type: RoadNodeType
world_coords: Tuple[int, int] = field(init=False)
def __post_init__(self):
# (Use config variables here, e.g. `config.TILE_WIDTH`, to calculate x and y)
# Hack to get around frozen=True. We don't care that we're mutating
# an "immutable" object on __init__().
object.__setattr__(self, "world_coords", (x, y))
这是我暂时使用依赖注入模型来解锁测试的权宜之计。请注意 RoadSegmentNode
现在如何拥有一堆仅用于初始化的新属性。这比保留对配置的引用要好一点,因为至少它们是明确的,但它仍然是一个非常糟糕的设计。
@dataclass(eq=True, frozen=True) # make hashable
class RoadSegmentNode:
# NOTE: DO NOT ACCESS THESE ATTRIBUTES!
grid_width: int
grid_height: int
tile_width: int
tile_height: int
road_width: int
tile_index: Tuple[int, int] # (r, c)
dir: Direction
node_type: RoadNodeType
world_coords: Tuple[int, int] = field(init=False)
def __post_init__(self):
# (Use attributes here, e.g. `self.tile_width`, to calculate x and y)
# Hack to get around frozen=True. We don't care that we're mutating
# an "immutable" object on __init__().
object.__setattr__(self, "world_coords", (x, y))
如何将配置传递给数据class进行初始化而不使其成为数据class的属性?我什至应该考虑为这个用例使用 dataclass 吗?我相信初衷是保持所有实例不可变,但我无法确认。
您应该将 config
定义为 init-only variable。这样它将传递给 __post_init__()
,但之后会消失:
from dataclass import dataclass, field
from typing import InitVar
@dataclass(eq=True, frozen=True)
class RoadSegmentNode:
tile_index: Tuple[int, int]
dir: Direction
node_type: RoadNodeType
world_coords: Tuple[int, int] = field(init=False)
config: InitVar[Config] # will not appear in instances
def __post_init__(self, config):
x, y = ..., ... # calculate using config
# looks hacky for sure, but is the right way to work with frozen dataclasses
object.__setattr__(self, "world_coords", (x, y))