Jus*_*yer 2 python python-3.x python-dataclasses
我有一个根级config类,我通过依赖注入在我的代码库中传递它。
问题是,我有这个数据类,需要此配置中的一些属性来world_coords计算__post_init__().
为了保持测试干净并避免其他测试导入问题(此处未讨论),我希望能够将配置直接传递给此对象,而不是从导入中读取这些值。然而,如果我将配置构建为参数,它就会成为数据类的一个属性,这是我试图避免的。实际上不需要RoadSegmentNode保留使用过的配置的引用。
这是该类的基本结构:
@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))
Run Code Online (Sandbox Code Playgroud)
这是我为了保持依赖注入模型而采取的权宜之计,以暂时解除我的测试障碍。请注意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))
Run Code Online (Sandbox Code Playgroud)
如何将配置传递给数据类进行初始化而不使其成为数据类的属性?我是否应该考虑这个用例的数据类?我相信最初的意图是保持所有实例不可变,但我无法确认。
您应该将其定义config为仅初始化变量。这样它就会被传递到__post_init__(),但之后就会消失:
from dataclasses import dataclass, field, 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))
Run Code Online (Sandbox Code Playgroud)