我想创建一个config
dataclass
,以简化对特定环境变量的白名单和访问(键入os.environ['VAR_NAME']
相对于config.VAR_NAME
是乏味的)。因此,我需要忽略dataclass
的{{1}}函数中未使用的环境变量,但是我不知道如何提取默认__init__
以便将其包装为例如还包含__init__
作为参数之一的函数。
*_
运行此命令可以给我import os
from dataclasses import dataclass
@dataclass
class Config:
VAR_NAME_1: str
VAR_NAME_2: str
config = Config(**os.environ)
。
答案 0 :(得分:0)
我只提供一个明确的__init__
而不是使用自动生成的@dataclass
class Config(init=False):
VAR_NAME_1: str
VAR_NAME_2: str
def __init__(self, **kwargs):
names = set([f.name for f in dataclasses.fields(self)])
for k, v in kwargs.items():
if k in names:
setattr(self, k, v)
。循环主体仅设置可识别的值,而忽略意外的值。
请注意,不过直到稍后,这都不会抱怨缺少默认值的情况。
Config.__init__
或者,您可以将经过过滤的环境传递给默认的field_names = set(f.name for f in dataclasses.fields(Config))
c = Config({k:v for k,v in os.environ.items() if k in field_names})
。
343 2224 S, 5434443 X, 5434 3434 T....
答案 1 :(得分:0)
在将参数列表传递给构造函数之前先对其进行清理,这可能是最好的方法。但我建议不要编写自己的__init__
函数,因为数据类的__init__
还会执行其他一些方便的操作,而这些操作会因覆盖而丢失。
另外,由于参数清除逻辑与类的行为紧密相关,并返回一个实例,因此将其放入classmethod
中可能是有道理的:
from dataclasses import dataclass
@dataclass
class Config:
var_1: str
var_2: str
@classmethod
def from_dict(cls, env):
return cls(**{k: v for k, v in env.items() if k in cls.__annotations__})
# usage:
params = {'var_1': 'a', 'var_2': 'b', 'var_3': 'c'}
c = Config.from_dict(params) # works without raising a TypeError
print(c)
# prints: Config(var_1='a', var_2='b')
答案 2 :(得分:0)
我结合了两个答案; setattr
可以成为性能杀手。自然,如果字典在数据类中没有某些记录,则需要为其设置字段默认值。
from __future__ import annotations
from dataclasses import field, fields, dataclass
@dataclass()
class Record(object):
name: str
address: str
zip: str = field(default=None) # won't fail if dictionary doesn't have a zip key
@classmethod
def create_from_dict(cls, dict_) -> Record:
class_fields = {f.name for f in fields(cls)}
return Record(**{k: v for k, v in dict_.items() i k in class_fields})