【问题标题】:Storing code inside a dictionary将代码存储在字典中
【发布时间】:2016-01-19 13:13:26
【问题描述】:

我正在学习 Python,尽管我正在编写自己的脚本,该脚本允许我检查程序运行时提供的参数。下面是我想要实现的示例:

python file.py -v -h anotherfile.py

./file.py -v -h anotherfile.py

在这两种情况下,-v-h 参数打印出模块版本和基本帮助文件。我已经有了区分参数和文件的代码,除了我想创建一个关于这个问题的通用模块。

以下用Java编写的代码-

// Somewhere.
public static HashMap<String, Runnable> args = new HashMap<String, Runnable>();
public void addArgument(String argument, Runnable command) {
    if (argument.length() > 0) {
        if (args.get(argument) == null) {
            args.put(argument, command);
        } else {
            System.err.println("Cannot add argument: " + argument + " to HashMap as the mapping already exists.");
            // Recover.
        }
    }
}

// Somewhere else.
foo.addArgument("-v", () -> {System.out.println("version 1.0");});
foo.args.get("-v").run();

-将成功运行 Lambda 表达式(至少这是我在研究该主题时读到的)。但是我不知道 Lambda 表达式是如何工作的,并且只有基本的使用知识。

这个问题的重点是,如何在 Python 中实现类似于 Java 示例的功能,将任何类型的代码存储在数组中?

问题在于Java示例,如果我在执行addArgument的类中定义了int i = 0;并以某种方式使用i,则包含addArgument的类知道使用i调用它的一个。我担心 Python 的情况可能不一样......

我希望能够将它们存储在字典或其他某种基于键的数组中,因此我可以按以下方式存储它们:

# Very rough example on the latter argument, showing what I'm after.
addoption("-v", print("version 1.0"))

编辑:我想要的示例:(不按原样工作)(请忽略 ;'s)

args = {};

def add(argument, command):
    args[argument] = lambda: command;  # Same problem when removing 'lambda:'

def run():
    for arg in args:
        arg();  # Causing problems.

def prnt():
    print("test");

add("-v", prnt);
run();

【问题讨论】:

    标签: python function dictionary lambda


    【解决方案1】:

    编辑:要更正您最近的代码,迭代字典会产生它的键而不是它的值,所以你需要:

    args = {};
    
    def add(argument, command):
        args[argument] = command;
    
    def run():
        for arg in args:
            args[arg]()     # <<<<<<<<<<
    
    def prnt():
        print("test");
    
    add("-v", prnt);
    run();
    

    对于您给出的示例,函数字典虽然可能,但并不是在 Python 中处理事情的自然方式。标准库有一个模块 argparse 专门用于处理所有与命令行参数相关的事情,而不是使用字典的键,您可以解析命令行参数并引用它们存储的常量。

    import argparse
    
    def output_version():
        print('Version 1.0!')
    
    parser = argparse.ArgumentParser(description="A program to do something.")
    parser.add_argument('-v', help='Output version number.', action='store_true')
    
    args = parser.parse_args()
    if args.v:
        output_version()
    

    (实际上输出版本字符串也由argparse本地处理:参见here)。

    要打印出一个文本文件的内容,myfile.txt 在给出-p 开关时:

    import argparse
    
    def print_file(filename):
        with open(filename) as fi:
            print(fi.read())
    
    parser = argparse.ArgumentParser(description="A program to do something.")
    parser.add_argument('-p', help='Print a plain file.', action='store')
    
    args = parser.parse_args()
    
    if args.p:
        print_file(args.p)
    

    与例如一起使用

    $ prog.py -p the_filename.txt
    

    【讨论】:

    • 如何将纯文件的内容打印为参数的操作?
    • 您可以定义一个函数来执行此操作,然后在参数解析器包含相应的开关时调用它。你也想在命令行中指定文件名吗?
    • 当然。我正在创建一个通用模块,我可以在其中任何和所有参数和文件指定任何操作。
    • 您当然可以指定将哪个文件名传递给打印函数(请参阅我的编辑)...但也许我不明白:您是否要传递要在命令行上执行的代码?
    • 天哪,我爱你('nuff 说
    【解决方案2】:

    在 Python 中,您可以简单地将函数的引用用作数据结构中的值。例如,考虑以下代码:

    def spam():
        print('Ham!')
    
    eggs = [spam, spam, spam]
    for x in eggs:
        x()
    

    这将调用函数spam 的三个实例。

    您所指的lambda expressions 只是定义函数的另一种方式,无需显式地将它们绑定到名称。考虑以下几点:

    eggs = [lambda : print('ham'), lambda : print('spam')]
    for x in eggs:
        x()
    

    但是,当您使用参数时,这会变得更加强大:

    fn = [lambda x: return x + 3, lambda x: return x * 2]
    for f in fn:
        print(f(4))
    

    一旦你有一个函数的引用,你就可以将那个传递给另一个函数。

    def foo(x):
        return x + 2
    
    bar = lambda x: return x * 2
    
    def h(g, f, x):
        return g(f(x))
    
    print(h(foo, bar, 37))
    

    但是,在您的场景中,您可以简单地传递 lambda : print("version 1.0")

    【讨论】:

    • 第一个例子!有没有办法可以将spam() 作为def 的参数?
    • 类似def foo(boo): boo()
    • 当然(假设我理解正确)。我会更新我的答案。编辑:是的,正是如此。
    • Uhhh.. 我有点迷失在编辑中?它是如何工作的?
    • 它显示了函数foobar的定义(都使用deflambda),然后将这些函数传递给另一个函数h。然后函数h 依次调用它们(即将结果从f 传递给g)。结果被打印出来。在调用h时,我们为f填写函数foo,为g填写bar,但你现在可以使用h来组合任意两个函数(假设前者输出的东西后者可以作为输入处理)。
    【解决方案3】:

    由于在 Python 中函数是一等对象,您可以创建 {string: callable} 对的字典。

    def help():
        print("Usage: xyz")
    
    
    d = {
        'help': help,
        'version': lambda: print("1.0"), # lambda is also callable
    }
    

    定义后的用法如下:

    my_function = d["help"]  # retrieves function stored under key 'help' in dict
    my_function()  # calls function
    
    # or obviously you may drop explainatory variable
    d['help']()
    

    它适用于您的自定义解决方案,具有这样定义的问题。

    对于创建命令行界面的标准化方法,您可能需要熟悉argparse module

    【讨论】:

    • 我可以将其修改为:addargument(arg, function),将函数托管在不同的模块中并使用addargument("-v", argnamegoeshere) 调用它吗?
    【解决方案4】:

    Python 有一个名为 eval() 的函数,它接受字符串并尝试将它们作为代码进行评估。

    >>> eval("2+3")
    5
    

    然后您可以使用 3 个引号将代码存储为多行字符串

    x = """the quick brown fox
    jumps over the
    lazy dogs"""
    

    如果你想自己存储函数,没有理由不能将它们也放入字典中。即使没有 lambda。

    def f():
        return 1
    
    def g(x):
        return x + 1
    
    def h(x):
        return 2*x
    
    F = [f,g,h]
    G = {"a": f, "b": g, "c": h}
    
    (F[0](), G["a"]())
    

    元组的值为(1,1)。否则我不知道你在问什么。

    【讨论】:

    • @frayment Python 并没有真正做到这一点。您可以存储函数,也可以将代码存储为字符串并计算它们。
    • 嗯,前者是我想要达到的目标。
    • @frayment 我的示例现在包括一个list 函数和一个dictionary 函数。这行得通吗?
    • 最后一个例子是我正在寻找的部分。问题是,您已将这些值硬编码到位。我希望能够调用一个函数,该函数指定我的方法作为参数运行,然后将该参数动态存储在字典中。
    • @frayment 也许这些方法会对你有所帮助。祝你好运!
    猜你喜欢
    • 1970-01-01
    • 2016-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-31
    • 1970-01-01
    • 2011-05-13
    • 1970-01-01
    相关资源
    最近更新 更多