This answer explains how to create test cases dynamically.
The answer's code:
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))
I've tested and it works, but I can't just figure out how?
I have trouble understanding the lambda self:
magic in play here, mainly:
functools.partial()
(i.e. to create a wrapper function with one extra parameter that is not yet known)self
a meaningful keyword or would lambda spam
would work just as well?.check()
is perfectly fine outside the class
es scope?lambda
(not to mention that I agree with Guido and Alex that it is an eyesore and I want to do without :)Lamda Functions (also referred to as Anonymous Function in Python) are very useful in building Tkinter GUI applications. They allow us to send multiple data through the callback function. Lambda can be inside any function that works as an anonymous function for expressions.
λ-expressions (λ is the small Greek letter lambda) are a convenient way to easily create anonymous functions — functions that are not named and can therefore not be called out of context — that can be passed as parameters to higher order functions like map, zip etc.
Lambda functions are syntactically restricted to return a single expression. You can use them as an anonymous function inside other functions. The lambda functions do not need a return statement, they always return a single expression.
Use a Lambda when you need to access several services or do custom processing. As data flows through services, you use Lambdas to run custom code on that data stream. This is useful in a Kinesis Pipeline that's receiving data from things like IoT devices.
First of all: The lambda is returned from a function to prevent that modified values of i
and j
will be used later.
Compare to the following:
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))
This will not work as expected, as all the lambdas will share the same namespace and will use the values of i
and j
after the end of the loop. If we use a separate function call, we introduce a new closure every time that captures the values of i
and j
at the point in time where the function is called.
We could achieve the same by saving the current values of i
and j
as default arguments of the lambda. For good measure, let's also use itertools.product
to avoid the nested loop:
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))
Is the lambda used here to perform the exact opposite of functools.partial() (i.e. to create a wrapper function with one extra parameter that is not yet known)
Not really. It just calls the check(i, j)
method on whatever it is given as an argument. This is used here to dynamically add methods to the Tests
class.
Is self a meaningful keyword or would lambda spam would work just as well?
spam
would work just as well. They choose self
here due to convention because the lambda represents a method.
What point is that lambda evaluated?
As soon as test_[i]_[j]()
is called on an instance of Tests
.
How come the .check() is perfectly fine outside the classes scope?
Because it's inside a lambda will only be called later with an instance of Tests
as the self
argument.
a_function = lambda x: do_something_with(x)
is equivalent to
def a_function(x):
return do_something_with(x)
In your particular example, the functions created are instance methods. Thus for example you could write:
class Tests:
...
test_1_2 = lambda self: self.check(1, 2)
which would be equivalent to:
class Tests:
...
def test_1_2(self):
return self.check(1, 2)
Now, since the identifiers are generated dynamically, hence use of setattr
.
- Is the lambda used here to perform the exact opposite of
functools.partial()
(i.e. to create a wrapper function with one extra parameter that is not yet known)
No, not really. In fact partial
could be used here as well.
test_1_2 = lambda self: self.check(1, 2)
would became
test_1_2 = partial(Tests.check, i=1, j=2)
- Is self a meaningful keyword or would lambda spam would work just as well?
Instance method's first argument always needs to be the instance. The convention is to name that parameter self
, but you can use any other name. I would not advise it, as it will make your code harder to read and understand.
- What point is that lambda evaluated?
lambda
creates anonymous function, which as any function is evaluated upon call.
- How come the .check() is perfectly fine outside the classes scope?
It isn't. It's self.check()
, where self
is an instance of Tests
class.
lambda returns a function. self
is its argument, and i and j are enclosed inside of it
So, ch(i, j) is a function of i and j which returns a function of self.
self does not have any magical meaning here as nothing in Python - every variable and function are explicit except of some built-ins. But as soon as these methods are attached to class, self becomes their 1st argument.
This means
after the loop The Tests class gets multiple methods called check_i_j
each of them has values i and j enclosed in it
each of them has their 1st param called self
which is good cause they are defined inside of class, they are instance methods, and thus their 1st parameter should be called self by convention
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With