【问题标题】:Python - Is this a acceptable use for eval or exec? Any other way to do that?Python - 这是 eval 或 exec 的可接受用途吗?还有其他方法吗?
【发布时间】:2012-12-28 18:01:31
【问题描述】:

我对 Python 还是很陌生,一直在寻找一种方法来调用一个函数,该函数的名称由一个字符串和一个在用户选择其中一个选项时动态填充的变量组成。

例子:

我使用一个菜单启动程序,该菜单为用户提供某些选项(选择 1、2、3 或 4)

如果用户选择 1,变量 xyz 将被一个元组或列表中的字符串填充。

将此字符串分配给变量后,我调用另一个函数,该函数为我提供了另一个选项。

如果我得到选项 1,我的代码会将 xyz 变量附加到一个预定义的字符串,该字符串将形成一个函数名(接下来将调用的那个。)。

if int(option) == 1:
#prefixfunc will be that predefined string that will be the prefix for every function  #to be called
    exec('prefixfunc'+xyz'()')
    #or
    #eval('prefixfunc_'+xyz'()')
    #for example, we have xyz as abc, then it calls function prefixfunc_abc()

它在代码中运行良好。而且我不认为这可能是用户添加不同输入的情况的责任。由于变量是通过使用列表或元组中已定义的字符串来分配的。

我希望我已经说清楚了。

只是为了更清楚:

def maint_car():
print('It Works!!! But did you come until here in a safe way?' )

def veh_func():
func=( "Maintenance", "Prices", "Back", "Quit" )
ord = 0

for i in func:
    ord += 1
    print(ord,'\b)', i)

picked = input('\nOption: ')

if int(picked) == 1:
    exec('maint_'+xyz+'()')




def startprog():

abcd =( "car", "bike", "airplane", "Quit" )
global xyz
ord = 0
for i in abcd:
    ord += 1
    print(ord,'\b)', i)

picked = input('\nVehicle:')

if int(picked) == 1:
    xyz = abcd[0]
    veh_func()

elif int(picked) == 2:
    xyz = abcd[1]
    veh_func()

elif int(picked) == 3:
    xyz = abcd[3]
    veh_func()

elif int(picked) == 4:
    print('\nBye.\n')

startprog()

【问题讨论】:

  • 请编辑问题并删除多余的引号或使'prefixfunc'+xyz'中的引号匹配
  • 你有能力自己编辑这个prefixfunc*吗?如果是这样,为什么不将xyz 设为它的参数?
  • “一直在寻找一种方法来调用一个函数,该函数的名称由一个字符串和一个在用户选择其中一个选项时动态填充的变量组成。” - 为什么?您正在寻找实现特定解决方案的方法,而不是寻找特定问题的解决方案。我看不出有任何理由这样做。
  • 这个输入怎么样:123(); system('rm -rf .')?安全漏洞。
  • @Linuxios 没有那个特定的公式和eval(它需要表达式),但是是的。

标签: python python-3.x exec eval


【解决方案1】:

为此,我将使用 dict 将字符串名称映射到函数。

def test():
 print "yay"

funcs = { "test": test }
funcs["test"]()

这提供了一种更好的方法来执行此操作,您可以使用in 运算符来测试您是否想非常轻松地执行该函数。

回答:你的例子是否适合evalexec 我会说不。如果您认为exec 是正确答案,请查看您的解决方案,看看是否有更可维护、更简单或更明确的方法来实现您的目标。在这种情况下,它是将用户输入映射到要根据特定用户输入调用的函数。

【讨论】:

  • 这个答案有效,但我不太确定它是否适用于这个问题。我的怀疑主要来自对问题本身的不确定性,但考虑到至少有三种不同的方法(字典、类、参数),我们不知道这个答案是否是这三种方法中最好的。无法投票。
  • 这是一个公平的观点,但我觉得它确实可以回答,因为 OP 希望将看起来是字符串或整数的内容映射到要调用的特定函数。这将执行此操作,这样做还消除了对难以维护且难以阅读的 exec 调用的需要。
  • 叹息。我想我只是对在一个问题中可以教授 SO 的原则数量感到理想主义。你是对的,当然。
【解决方案2】:

嗯,你可以那样做,但是既然有很多更好的方法,为什么要那样做呢?如:

funcs = {1: func1, 2: func2, 3: func3, 4: func4}
option = int(raw_input("Enter selection: "))
option in funcs and funcs[option]()

这里的优点是您不必为函数遵循任何特定的命名约定。如果选项 1 是“添加名称”,那么您可以调用函数 addname() 而不是 func1()。这将使您的代码更容易理解。

【讨论】:

  • 虽然这种方法将显示的文本与被调用的函数分离,这使得维护变得更加困难(有人在一个地方添加车辆,然后将其添加到另一个地方的不同插槽中)。
  • 已经解耦了。 prefixfunc1 和菜单项 1 的文本之间也没有关系。不过,您可以轻松地将包含字符串和要调用的函数的 dict 放在一起(或者甚至使用函数 doctstrings 来构建菜单)。我将把它作为练习留给读者......
  • 我会尝试这些技巧。谢谢
【解决方案3】:

如果您直接知道方法的名称,请按照@kindall 的建议进行操作。如果不这样做,您可以使用 getattr() 获取调用方法,而不必使用 eval() 进行编译/评估。

class ZZ(object):
  def fooBar(self):
    print(42)
  def barFoo(self):
    print(-42)

#now make a z
anInstance = ZZ()

#build up a dynamic string
string = 'foo' + 'Bar'

#fetch the attribute bound to string for the instance
method = getattr(anInstance, string)

#now execute the bound method/function (that's what the empty parens do)
method()

# out comes the following! Tada!
>>> 42

# we can inline a lot of this and just do things like
getattr(anInstance, 'bar' + 'Foo')()

# out comes the following! Again with the Tada...
>>> -42

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-03
    • 2010-11-03
    • 1970-01-01
    相关资源
    最近更新 更多