8

这个答案解释了如何动态创建测试用例。

答案代码:

class Tests(unittest.TestCase):
    def check(self, i, j):
        self.assertNotEquals(0, i-j)

for i in xrange(1, 4):
    for j in xrange(2, 6):
        def ch(i, j):
            return lambda self: self.check(i, j)
        setattr(Tests, "test_%r_%r" % (i, j), ch(i, j))

我已经测试过并且它有效,但我无法弄清楚如何

我很难理解lambda self:这里的魔法,主要是:

  1. 此处使用的 lambda 是否与执行完全相反的操作(即使用一个未知的额外functools.partial()参数创建包装函数)
  2. self一个有意义的关键字还是lambda spam同样有效?
  3. 那个 lambda 的评估点是什么?
  4. 为什么在es 范围.check()之外完全没问题?class
  5. 如果没有lambda ,你如何做到这一点?- 如果我理解正确,你应该可以不用lambda(更不用说我同意 Guido 和 Alex 的观点,这一个令人眼花缭乱的东西,我不用 :)
4

3 回答 3

5

首先:从函数返回 lambda 以防止修改后的值i并将j在以后使用。

与以下内容进行比较:

for i in xrange(1, 4):
    for j in xrange(2, 6):
        setattr(Tests, "test_%r_%r" % (i, j), lambda self: self.check(i, j))

这不会按预期工作,因为所有 lambda 将共享相同的命名空间,并将使用循环结束后的ij。如果我们使用单独的函数调用,我们每次都会引入一个新的闭包,该闭包捕获函数被调用的时间点的ij

i我们可以通过将和的当前值保存j为 lambda 的默认参数来实现相同的目的。为了更好地衡量,让我们也使用itertools.product来避免嵌套循环:

from itertools import product
from operator import methodcaller

for i, j in product(range(1, 4), range(2, 6)):
  setattr(Tests, "test_%r_%r" % (i, j),
          lambda self, i=i, j=j: self.check(i, j))

此处使用的 lambda 是否与 functools.partial() 完全相反(即使用一个未知的额外参数创建包装函数)

并不真地。check(i, j)它只是在作为参数给出的任何内容上调用该方法。这在这里用于向Tests类动态添加方法。

self 是一个有意义的关键字还是 lambda spam 也能正常工作?

spam也可以。他们之所以选择self这里是因为约定俗成,因为 lambda 代表一种方法。

那个 lambda 的评估点是什么?

只要test_[i]_[j]()在 的实例上被调用Tests

为什么 .check() 在类范围之外完全没问题?

因为它在一个 lambda 中,所以以后只会以 的实例Tests作为self参数调用。

于 2012-04-27T13:35:13.413 回答
5

a_function = lambda x: do_something_with(x)

相当于

def a_function(x):
    return do_something_with(x)

在您的特定示例中,创建的函数是实例方法。因此,例如,您可以编写:

class Tests:
...
   test_1_2 = lambda self: self.check(1, 2)

这相当于:

class Tests:
...
   def test_1_2(self):
       return self.check(1, 2)

现在,由于标识符是动态生成的,因此使用setattr.


  1. 此处使用的 lambda 是否与执行完全相反的functools.partial()操作(即使用一个未知的额外参数创建包装函数)

不,不是。实际上partial也可以在这里使用。

test_1_2 = lambda self: self.check(1, 2)

会变成

test_1_2 = partial(Tests.check, i=1, j=2)
  1. self 是一个有意义的关键字还是 lambda spam 也能正常工作?

实例方法的第一个参数总是需要是实例。约定是命名该参数,self但您可以使用任何其他名称。我不建议这样做,因为它会使您的代码更难阅读和理解。

  1. 那个 lambda 的评估点是什么?

lambda创建匿名函数,与任何函数一样在调用时对其进行评估。

  1. 为什么 .check() 在类范围之外完全没问题?

它不是。它的self.check(),哪里selfTests类的一个实例。

于 2012-04-27T13:50:41.857 回答
3

lambda 返回一个函数。self是它的参数,并且 i 和 j包含在其中

因此,ch(i, j) 是i 和 j的函数,它返回self的函数。

self 在这里没有任何神奇的含义,因为在 Python 中什么都没有——每个变量和函数都是显式的,除了一些内置函数。但是一旦这些方法被附加到类, self 就成为他们的第一个参数。

这表示

  • 在循环之后 Tests 类获得了多个名为 check_i_j 的方法

  • 它们中的每一个都有值 i 和 j包含在其中

  • 他们每个人都有他们的第一个参数self,这是很好的,因为它们是在类内部定义的,它们是实例方法,因此它们的第一个参数应该按照惯例称为 self

于 2012-04-27T13:27:39.090 回答