我目前正在做一些工作,希望将配置从yaml加载到类中,以便指定类属性。根据我所做的工作,我有一个不同的配置类。
在类中,我预先指定了预期的参数,如下所示,然后使用BaseConfig::load_config()从文件中加载数据。这将检查类在使用setattr()分配值之前是否具有相应的属性。
class AutoencoderConfig(BaseConfig):
def __init__(self, config_path: Path) -> None:
super().__init__(config_path)
self.NTRAIN: Optional[int] = None
self.NVALIDATION: Optional[int] = None
# ... more below
self.load_config()当我在其他脚本中引用AutoencoderConfig的属性时,我可能会说:config.NTRAIN。虽然这样做很好,但是Mypy不喜欢这样,并给出了以下错误:
path/to/file.py:linenumber: error: Unsupported operand types for / ("None" and "int")出现此错误是因为在进行检查时,尚未加载来自yaml文件的值,而且类型是用self.NTRAIN: Optional[int] = None指定的。
无论如何,我可以避免这种情况,而不必将:# type: ignore放在我所引用的config类的每一行末尾吗?
有使用这样的配置类的最佳实践吗?
编辑:
解决方案:
下面@SUTerliakov提供的解决方案非常好。最后,我决定采用一种@dataclass方法:
from dataclasses import dataclass, field
@dataclass
class BaseConfig:
_config: Dict[str, Any] = field(default_factory=dict, repr=False)
def load_config(self, config_path: Path) -> None:
...
@dataclass
class AutoencoderConfig(BaseConfig):
NTRAIN: int = field(init=False)
NVALIDATION: int = field(init=False)
# ... more below这允许我将每个变量指定为field(init=False),这似乎是解决问题的一个很好、明确的方法。
发布于 2022-04-12 21:38:00
在调用int之后总是load_config吗?(它能保持一种状态吗?)
如果总是int,那么不要将它们标记为Optional,也不要分配None。只需在类主体中声明它们而不进行初始化:
class AutoencoderConfig(BaseConfig):
NTRAIN: int
NVALIDATION: int
def __init__(self, config_path: Path):
super().__init__(config_path)
# Whatever else
self.load_config()否则,您必须在操作之前显式检查None。对于这种情况,type: ignore是一个糟糕的解决方案,因为这只会使真正的问题安静下来:Optional被用来表示变量可以是None,而不能将None除以整数,因此它可能会导致运行时问题。在这种情况下,适当的解决方案如下:
if self.NTRAIN is not None:
foo = self.NTRAIN / 2
else:
raise ValueError('NTRAIN required!')
# Or
# foo = some_default_foo
# If you can handle such case如果您知道在某个点之后它不可能是零,那么最干净的就是像这样assert它:
assert self.NTRAIN is not None
foo = self.NTRAIN / 2这两种方法都会使mypy高兴,因为NTRAIN实际上不是条件分支中的None,也不是assert之后的。
编辑:对不起,我可能误解了你的问题。load_config需要hasattr(AutoencoderConfig, 'NTRAIN')才能真正工作吗?如果是这样的话,最简单的解决方案是
class AutoencoderConfig(BaseConfig):
NTRAIN: int = None # type: ignore[assignment]
NVALIDATION: int = None # type: ignore[assignment]
def __init__(self, config_path: Path):
super().__init__(config_path)
# Whatever else
self.load_config()您不需要任何其他类型-忽略这种方式。
https://stackoverflow.com/questions/71197155
复制相似问题