在字典中存储函数 [Python]

9

我目前正在构建一个应用程序,需要迭代一系列步骤,这些步骤基本上做相同的事情,只有很少的代码不同(约15行)。步骤的数量将根据项目的配置而变化,因此为每个可能的实例创建单独的函数似乎有点愚蠢。

在JavaScript中,我会这样做:

var switches = [true, true, false, true];

var holder = {
    0: function() { /* do step0 */ }
    1: function() { /* do step1 */ }
    2: function() { /* do step2 */ }
    3: function() { /* do step3 */ }
    // ...etc...
}

for (var i = 0; i < switches.length; i++)
    if (switches[i])
        holder[i]();

有没有一种类似于Python的方法可以做到这一点?我能想到的唯一办法就是像这样:
switches = [True, True, False, True]

class Holder(object):
    @staticmethod
    def do_0():
        # do step0

    @staticmethod
    def do_1():
        # do step 1

    # ...etc...

    def __repr__(self):
        return [self.do_0, self.do_1, ...]

for action in Holder:
    action()

如果我的步骤数量很多,这似乎非常低效。有没有更好的方法来处理这个问题?


装饰器可能更符合您的需求。 - Padraic Cunningham
最好的方法是什么?如果我使用相同的装饰器定义所有函数,有没有简单的方法可以循环遍历它们而不创建列表进行循环? - Robert Ingrum
4个回答

3
您可以按照以下方式进行操作:
# define your functions
def fun1():
    print("fun1")

def fun2():
    print("fun2")

def fun3():
    print("fun3")


switches = [True, False, True];

# put them in a list (list makes more sense than dict based on your example)
func_list = [fun1, fun2, fun3]

# iterate over switches and corresponding functions, and execute 
# functions when s is True    
for s,f in zip(switches, func_list):
    if s: f() 

这只是其中一种方法,还有其他很多方法,例如使用lambda表达式、使用字典等等。
如果你的函数只有一行,你可以使用lambda表达式来实现:
func_list = [lambda: print("lambda1"), 
             lambda: print("lambda2"), 
             lambda: print("lambda1")]

1
你的代码肯定是可以工作的,但我正在尝试避免在字典范围之外定义一堆函数。否则,我可以直接使用我已经有的代码。不幸的是,我正在处理的代码比这个例子要复杂得多,如果定义了一堆函数,很快就会使代码难以阅读。 - Robert Ingrum
1
我添加了lambda的示例。但是并不是所有东西都可以放入lambda中。 - Marcin
3
Python没有像JS一样的匿名函数。是的,Python有lambda表达式,但是它们只能限制在单个表达式中使用。 - pzp
@pzp1997 你知道Python中是否有与闭包相当的东西吗?不幸的是,我正在尝试从PHP转向Python,但这似乎相当受限制。 - Robert Ingrum
Python 中有闭包(参见:http://blaag.haard.se/Python-Closures-and-Decorators--Pt--1/)。我还会查找装饰器,因为它们与闭包非常相关。 - pzp
显示剩余2条评论

2
看起来在Python中没有这样做的方法,这是一个有意为之的设计决策,因为它被认为不符合Python的风格。哦,好吧,看来我必须定义这些方法,然后手动将它们添加到列表中以进行迭代。
来源:https://softwareengineering.stackexchange.com/a/99245

1
- Your functions don't need to be enveloped in a utility class.
- I don not see how the two blocks of code differ in efficiency.
- You can use enumerate and lambdas to simplify your code.

简化代码
d = {0: lambda: 'Performing Step 0',
     1: lambda: 'Performing Step 1',
     2: lambda: 'Performing Step 2',
     3: lambda: 'Performing Step 3',
     4: lambda: 'Performing Step 4'}

for index, switch in enumerate([1, 0, 1, 1, 0]):
    if switch == 1: d[index]() 

我提供的示例大大简化了问题。在我的实际样本中,Holder类实际上只是一个辅助类,用于保存步骤处理器的所有设置。我最初也研究了使用lambda表达式,但看起来它们不能太复杂(即对于15行代码不起作用)。 - Robert Ingrum

-1
我通常会按照以下方式进行。我喜欢这种方法,因为它在代码中增加了最少的打字开销,如果您以后编写了其他方法,文件中不需要修改任何内容。
def steptest0():
    code
def steptest1():
    code
def steptest2():
    code

...

tests = filter(lambda x: x.startswith('steptest'),
               dir())
for t in tests: eval(t + '()')

在Python中,每个方法都已自动放入字典中,而dir()让我们可以访问它。

免责声明。对于使用“eval”的普通行人狂热者来说,大多数警报都开始拉响甚至可能抽搐。他们可以通过使用反射机制来保护自己免受eval的影响(这可能会使其更难以阅读,但仍然值得,因为他们不能被指控使用“eval”)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接