使用for循环定义多个函数——Python

新手上路,请多包涵

假设我需要创建 10 个名为 add1、add2、…、add10 的函数。对于每个 i , addi 接受一个整数 x 并输出 x+i

当我尝试以下操作并评估 add2(10) 时,Python 给了我一个 NameError。

 for i in range(10):
    def addi(x):
        return x + (i+1)

我知道上面的代码是错误的,因为我定义的 addi 函数是不可变的;我很确定我所做的就是重新定义 addi 10 次。如何快速定义这 10 个功能?

原文由 jessica 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.4k
2 个回答

在这种情况下使用 functools.partial 结合字典。

我假设你 真正 想做的更复杂,因为这个特定任务不需要多个函数。

 from functools import partial

def add(x, i):
    return x + i

d = {f'add{k}': partial(add, i=k) for k in range(1, 10)}

d['add3'](5)  # 8

解释

  • 将可变数量的相关对象存储在专门定义的字典中是一种很好的做法。
  • functools.partial 是一个高阶函数,它返回一个固定选定参数的输入函数。

污染命名空间

从评论中,一个常见的问题是:

OP 似乎在问是否有更好的方法来做 def add1:def add2: … 虽然我同意你的解决方案,但我不同意它是当前问题的解决方案。 - MooingRawr

为什么使用迭代器来定义函数是个坏主意?对我来说,这似乎是缩短代码的好方法。通常一一定义它们会更好吗? – 杰西卡

我的简短回答:

使用 globals().update 污染命名空间是个坏主意。将相关变量保存在特制的集合中。从任何角度(可维护性、调用、修改等)来看它都是有意义的。 – jpp

@BoarGules 的扩展答案:

这不是一个好主意,因为它动态创建函数,但它们只能由静态代码调用(否则代码不知道调用什么),那么它们是动态的有什么意义呢?动态创建它们会使代码难以阅读(您无法轻松搜索函数定义),并给 IDE 在帮助您的过程中带来不必要的麻烦。您节省了繁琐、重复的编码,但编程有时需要繁琐而仔细的重复。努力和技能最好用于加速编码(聪明的搜索/替换,宏,等等)。 – BoarGules

原文由 jpp 发布,翻译遵循 CC BY-SA 4.0 许可协议

函数一般是不可变的;但他们可能引用了数据。在您的代码片段中,这个引用有点不清楚,但是 i 只在函数体中出现一次,作为读取。因此,它从一些外部范围读取,通常是您的 for 循环包含在其中的函数或模块。因为这恰好是一个共享上下文,所以每个 addi 函数都将以相同的 i 结束。

另一个问题是您在每次迭代中都使用名称 addi ,并且该函数从未以其他名称出现。因此,之前定义的任何 addi 函数都将丢失。这就引出了第三个问题;为什么要动态创建名称(例如函数名称)?使用集合几乎总是更好,例如 jpp 答案中的 d 字典。否则,什么代码甚至会引用您创建的函数?

尽管如此,仍然可以按照您的要求进行操作,尽管这很奇怪。这是一种方法:

 def addfunc(n):
    def addn(x):
        return x+n
    return addn

for i in range(1,10):
    globals()['add{}'.format(i)] = addfunc(i)

这会滥用 globals 将动态创建的名称注入模块的命名空间,并将这些函数中的每一个嵌套在另一个函数中以创建包含它们各自的 n 值的命名空间。另一个经典的 hack 是使用默认参数, 部分应用 operator.add 是一种更简洁的函数式风格。

原文由 Yann Vernier 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题