【问题标题】:How to enable functions in script from what is specified in configuration file?如何根据配置文件中指定的内容启用脚本中的功能?
【发布时间】:2019-10-29 01:08:16
【问题描述】:

我有以下 JSON 文件:

{
    "add1":true,
    "add2":false,
    "add3":true
}

还有以下 Python 程序:

def add1(n): return n+1
def add2(n): return n+2
def add3(n): return n+3

def score(n):
    with open('file.json', 'r') as f:
        conf = json.load(f)
        for key, value in conf.items()
            if value == True:
                # add1 and add3 calls only because they're set to True
                return (add1(n) + add3(n))   

正如代码中所写,我只想在配置 JSON 文件中设置为 True 时调用这些函数。这是正确的方法吗?现有工具是否简化了这种方法,还是我必须手动编写每个案例?

【问题讨论】:

  • 如果配置文件中出现"screw_it":true 之类的内容,您希望发生什么?如果"add1":true"add1":false 都不存在怎么办?
  • @Goyo 我可能会提出一个我会发现的错误,但我希望用户不要乱用它并输入我将指示的布尔值。
  • 然后试试@S.Pellegrino proposes 之类的东西。它比使用evalglobals() 更安全、更易于维护。

标签: python json configuration


【解决方案1】:

你应该使用 eval:https://docs.python.org/3/library/functions.html#eval

def score(n):
   with open('file.json', 'r') as f:
       conf = json.load(f)
       sum = 0
       for key, value in conf.items():
           if value == True:
               sum += eval('{}({})'.format(key, n))
       return sum   

【讨论】:

    【解决方案2】:

    您可以将 for 循环替换为对 eval 的调用

    def score(n):
        with open('file.json', 'r') as file:
            conf = json.load(file)
            return sum(eval(f"{k}({n})") if v else 0 for k, v in conf.items())
    

    这假定您的 json 中的所有条目都映射到现有函数

    【讨论】:

    • 我的添加函数是一个更复杂问题的借口,我将其简化为可以理解的问题;我的第一个目标只是调用不同的函数,这些函数接受一个字符串作为参数并返回一个double 值。但它似乎不适用于字符串,eval 方法是否适用于作为参数给出的字符串?
    • @ooj-001 - eval 所做的就是将你放入其中的任何内容尝试作为 python 代码运行,所以是的
    • 好的,谢谢,您的f 是否特定于必须在eval 函数中写入的语法,或者您是否拼错了文件?因为在我的编辑器中,突出显示字母 f 的方式使其被理解为字符串。
    【解决方案3】:

    你可以这样做:

    import json
    
    def add1(n): return n+1
    def add2(n): return n+2
    def add3(n): return n+3
    
    defs = {
        'add1' : add1,
        'add2' : add2,
        'add3' : add3
    }
    
    def score(n):
       with open('file.json', 'r') as f:
           conf = json.load(f)
           return sum(function(n) for name, function in defs.items() if conf[name])
    

    如果你对 lambdas 没问题,你甚至可以使用:

    defs = {
        'add1' : lambda n: n+1,
        'add2' : lambda n: n+2,
        'add3' : lambda n: n+3
    }
    

    【讨论】:

    • 我用了你的方案,效果很好,非常感谢!
    • 我认为return 声明在with 块之外会更快乐。它与那里无关。
    【解决方案4】:

    @Sayse 有一个很好的方法,尽管我会更改 sum 行,这样我们就不需要在值为 false 时添加 0。

                return sum(eval(f"{key}({n})") for key, value in conf.items() if value)
    

    或者调用以字符串命名的函数的另一种方式是

                return sum(globals()[k](n) for k,v in conf.items() if v)
    

    我不确定 Python 的最佳实践是否偏爱一个版本。结果是一样的。

    请注意,您信任数据来指定程序调用的函数。不正确或恶意数据可能会导致不确定和有害的行为,因此您可能需要检查密钥以确保它们都指定了您打算以这种方式使用的功能之一。

    【讨论】:

    • 我会解析配置文件中的值,如果有问题会抛出异常,谢谢你的回答。
    猜你喜欢
    • 2021-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-15
    • 1970-01-01
    • 2019-12-30
    • 1970-01-01
    相关资源
    最近更新 更多