unittest.TestCase, lambda and __getitem__

Alex Martelli aleaxit at yahoo.com
Mon Sep 13 09:15:06 CEST 2004


Steven Bethard <steven.bethard at gmail.com> wrote:
   ...
> Previously, I had written some code like:
> 
> self.assertRaises(ValueError, lambda: method(arg1, arg2))
> 
> This was a simple fix because assertRaises takes *args and **kwds, so
> I fixed it to look like:
> 
> self.assertRaises(ValueError, method, arg1, arg2)
> 
> which is much cleaner anyway (and what I should have been doing from

Agreed.

> the start). Where I get uneasy is when I run into code like:
> 
> self.assertRaises(ValueError, lambda: obj[index])
> 
> Presumably, I could write this as:
> 
> self.assertRaises(ValueError, obj.__getitem__, index)
> 
> I guess this makes me uneasy because I'm not entirely certain that
> obj[item] is *always* translated to obj.__getitem__(index).  Is it? 

Yes.

> That is, is there any way that obj[item] would get translated into a
> different method call?

No.

> Or is there a better/clearer way of handling this kind of test case?

Sure:

    def wrong_indexing(): return obj[index]
    self.assertRaises(ValueError, wrong_indexing)

Whatever you can do with self.assertRaises(X, lambda: YZT) you can
(essentially idenfically) do with the two statements:

    def anyname(): return YZT
    self.assertRaises(X, anyname)

If you have a series of slightly different lambdas on several
assertRaises calls, you can reuse the same name (if that makes sense),
since another def for the same name simply rebinds the name, just like
multiple successive assignments to the same name would.  Often you may
respect "once, and only once" better by factoring several lambdas into a
single def with an argument or two, of course.  But for a mechanical
transformation changing each lambda into one def works just fine, and I
think it's preferable in terms of reliability to delving into internals
to find out what special methods get called when.

Besides, the delving approach may be far from trivial if you ever try to
translate something like lambda:x+y since in THAT case you cannot
necessarily tell what method gets called on what object (__add__ on x,
or __radd__ on y?) -- here you might try operator.add, but what then
about lambda:x+y*z ...?


Alex




More information about the Python-list mailing list