Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/316.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何将代码中的参数名与配置文件分离?_Python_Json_Function_Class - Fatal编程技术网

Python 如何将代码中的参数名与配置文件分离?

Python 如何将代码中的参数名与配置文件分离?,python,json,function,class,Python,Json,Function,Class,在我的代码中,我使用一个JSON文件来决定用于初始化对象的值 在myconfig.json中: { "ClassA": { "p1": 3, "p2"; 4 } } 我的ClassA: class ClassA: def __init__(self, p1, p2): self.p1 = p1 self.p2 = p2 然后我通过以下方式实例化ClassA: with open("config.json", "r") as f:

在我的代码中,我使用一个JSON文件来决定用于初始化对象的值

在my
config.json
中:

{
  "ClassA": {
    "p1": 3,
    "p2"; 4
  }
}
我的
ClassA

class ClassA:
    def __init__(self, p1, p2):
        self.p1 = p1
        self.p2 = p2
然后我通过以下方式实例化
ClassA

with open("config.json", "r") as f:
    config = json.load(f)

a = ClassA(**config["ClassA"])
现在,当JSON中与值相关联的键发生变化(例如,“p1”变为“p3”)时,就会出现问题;或者
ClassA
中的参数名称发生更改。因为任何更改都意味着使用上述实例化方法都会失败

为了将配置与代码解耦,我定义了另一个类来将配置参数名称映射到我的类参数名称,反之亦然

class IInitializable(ABC):
    _parameter_name_lookup = dict()

    @classmethod
    def parameter_name_lookup(cls, mode):
        if mode == "ConfigurationToClass":
            return {y: x for x, y in cls._parameter_name_lookup.items()}
        elif mode == "ClassToConfiguration":
            return cls._parameter_name_lookup
        else:
            raise NameError("No such mode")
现在假设我将我的
config.json
更改为:

{
  "ClassA": {
    "p1": 3,
    "p9"; 4
  }
}
class ClassA:
    def __init__(self, p1, p4):
        self.p1 = p1
        self.p2 = p4
和我的
ClassA
到:

{
  "ClassA": {
    "p1": 3,
    "p9"; 4
  }
}
class ClassA:
    def __init__(self, p1, p4):
        self.p1 = p1
        self.p2 = p4
我将让
ClassA
iInitializable
继承并定义映射:

class ClassA(IInitializable):
    _parameter_name_lookup = {"p4": "p9"}
    def __init__(self, p1, p4):
        self.p1 = p1
        self.p2 = p4
然后我可以使用新的
config.json
初始化我的
ClassA
,方法是:

with open("config.json", "r") as f:
    config = json.load(f)

config_to_class_lookup = ClassA.parameter_name_lookup("ConfigurationToClass")
new_parameters_for_a = dict()
for config_parameter_name, value in config.items():
    class_parameter_name = config_to_class_lookup.get(config_parameter_name, config_parameter_name)
    new_parameters_for_a[class_parameter_name] = value

a = ClassA(**new_parameters_for_a)

不过,我相信有一种更优雅的方法来解决这个问题。我已经阅读了我的元类和装饰器,似乎(?)这就是方向。但我似乎不能把所有的部分都放在一起

我觉得你把事情弄得太复杂了

更改API应该是您很少做的事情,而不是一直做的事情

您可能已经需要对配置文件进行版本设置,以便知道它们是为哪个API版本设计的

因此,如果您编写了从早期JSON模式迁移到当前模式的代码,您只需在
load
时间执行即可。然后,您的所有类只需担心如何从当前版本初始化。(据推测,如果他们也需要保存,您永远不需要保存旧版本,从而使这一半的问题不存在。)

从一个JSON模式版本迁移到另一个版本是一个常见的问题,已知的解决方案和大量的库可以帮助您。(更普遍的数据库迁移问题更为常见和众所周知。)

即使您想自己编写它也相对容易,不需要元类、装饰器或其他任何东西,只需根据硬编码规则递归地遍历和转换嵌套的dict/list结构(用于快速脏迁移)或在某种转换dict中查找(用于更干净的解决方案)

另外,这使得为迁移编写单元测试变得很容易,而不需要在所有类的所有版本的笛卡尔积之间进行一些复杂的集成测试。

看看这个: