【问题标题】:Using setattr to freeze some parameters of a method使用 setattr 冻结方法的某些参数
【发布时间】:2014-02-07 16:29:25
【问题描述】:

为了自动生成参数化测试,我试图通过冻结现有方法的一些参数来将方法添加到类中。这是一段 Python 3 代码

class A:
    def f(self, n):
        print(n)

params = range(10)

for i in params:
    name = 'f{0}'.format(i)
    method = lambda self: A.f(self, i)
    setattr(A, name, method)

但是,以下几行会产生相当令人失望的输出

a = A()
a.f0()

打印“9”(而不是“0”)。我一定做错了什么,但我看不出是什么。你能帮忙吗?

非常感谢


编辑:这个问题确实是重复的。我想感谢所有 cmets 的质量,这比原始答案要深得多。

【问题讨论】:

标签: python reference setattr


【解决方案1】:

试试

method = lambda self, i=i: A.f(self, i)

因为否则当你调用方法i的值可能已经改变了

【讨论】:

  • 这与变量作用域有关。 lambda 是一个简单的函数,其主体为 A.f(self, i)。当您使用此主体调用方法时,将请求 i 的值。它取自外部范围。在 SO 和 google 中搜索关闭
  • @Sebastien 这是因为没有=i 部分,i 的值将在 lambda 函数执行之前确定(在这种情况下,它与最近的分配给i 的值,在您的循环之后将是9)。事实上,所有 Python 函数都是如此,这也是在引用非局部变量时可能会出现问题的原因(但也是在声明函数使用的非局部值之前声明函数的原因)。 Python 中的作用域远不止这些,但它基本上就是这样工作的。
  • @Sebastien Python 变量实际上与 Java 变量非常相似(原语不是对象有一些奇怪之处,但不会影响常见操作)。像 C、C++ 这样的语言与 Python 和 Java 有很大不同。顺便说一句,Java 通过要求 ifinal(即不可修改)来回避这个问题的道德等价物(使用内部类而不是 lambda/closure)。
  • @Sebastien Scope 并不是真正的问题,而是评估时间。事实上,如果没有这种行为,在 Python 中编写闭包会困难得多。 (请注意,对于所有非局部变量,Python [3] 实际上默认为类似final 的行为;您可以修改变量的属性,就像在 Java 中使用 final 对象的非最终成员一样,但您不能分配与非局部变量不同的对象,而无需先在闭包内将变量声明为nonlocal。)
  • 还有global,其作用类似于nonlocal,但用于全局/模块级变量。它还有一个不同之处在于,虽然nonlocal x 语句在创建函数时要求x 存在于词法范围内,但global x 语句不存在(但如果您在执行时不创建变量模块,在函数中对该变量的所有使用都需要使用global x,即使您没有在其他函数中为它分配任何东西;虽然这种模式确实有一些用途[我记得将它与ply/@987654343一起使用@],这不是你想要经常做的事情)。
【解决方案2】:

在 Python 中“冻结”参数的最佳方法是使用functools.partial。它大致相当于 warwaruk 的 lambda 版本,但是如果你有一个有很多参数的函数但只想冻结其中的一两个(或者如果你只知道某些参数而不关心其余参数)使用 partial 是更优雅,因为您只需指定要冻结的参数,而不必在 lambda 中重复整个函数签名。

你的程序的一个例子:

class A:
    def f(self, n):
        print(n)

from functools import partial

for i in range(10): # params
    setattr(A, 'f{0}'.format(i), partial(A.f, n=i))

根据您使用的 Python 3 版本,您可能不需要在字符串格式占位符中包含 0;从 3.1 开始,iirc 应该会自动替换。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多