16

I'm trying to use assertions to show some invariants (mostly in testing) Thus i want to write something like the following:

values = [ range(10) ] 
expected_values = [ range(10) ]

map (lambda x: assert x[0] == x[1] ,zip( [ run_function(i) for i in values ], expected_values))

If I use this with unittest.assertEqual this works perfectly fine , but if I want to write this with an assertion it just fails. Is there a way to fix this?

5 Answers 5

16

From the documentation:

Note that functions created with lambda forms cannot contain statements.

assert is a statement.

So no, you cannot use the assert statement in a lambda expression.

Sign up to request clarification or add additional context in comments.

2 Comments

No, you are not using the assert statement. You are achieving a similar effect by throwing the error, but that doesn't invalidate what I said.
Of course I'm hacking it - you cannot use a statement, as you said.
12

Unfortunately, assert is a statement and Pythons limited lambdas don't allow that in them. They also restrict things like print.

You can use a generator expression here though.

assert all(x[0] == x[1] for x in  zip( [run_function(i) for i in values ], expected_values))

I personally think that the following would be more readable

assert all(run_function(i) == j for i,j in zip(inputs, expected_values))

1 Comment

Here is something else you can do to actually assert: stackoverflow.com/a/40286356/78234
7

Actually you can:

assertion_raiser = lambda: (_ for _ in ()).throw(AssertionError("My Lambda CAN raise an assertion!"))

Here is some validation:

try:
    assertion_raiser()
except AssertionError:
    print("assertion caught")

1 Comment

Interesting it doesn't look very readable though. I guess I'd rather wrap an assertion into a function or write my own assert function that allows me to put it in a lambda.
1

Worked in my application, which was similar:

def _lambda_assert(fn, *args, **kwargs):
    def _assert(fn_out):
        if isinstance(fn_out, (list, tuple)):
            value, fail_msg = fn_out
            assert value, fail_msg
        else:
            assert fn_out  # value only
    return lambda: _assert(fn(*args, **kwargs))
    # return lambda x: _assert(fn(*args, **kwargs))  # for pytest; need dummy positional

Usage example:

import numpy as np

def _test_precision(size, atol=1e-2):
    x = np.random.randn(size)
    y = np.random.randn(size)
    absdiff = np.abs(x - y)
    fail_msg = f"absdiff: {absdiff}; atol={atol}"
    return np.allclose(x, y, atol=atol), fail_msg

lambda_assert = _lambda_assert(_test_precision, 20, atol=1)

3 Comments

That would make erros messages harder though? As you evaluated the expression before the assert.
@Alex This is only a minimal example; the key that's shown is to effectively wrap the assertion in a callable via a local function definition - how value and fail_msg are derived is highly flexible. For example, I actually fetched both from yet another function: value, fail_msg = _fn(), where _fn() is arbitrarily complex. It was among the few things I had to craft to hack around PyTest's various requirements.
@Alex Admittedly my example wasn't very clear - updated answer
0

One simple solution is to define a auxiliary function that raises an assert given an input boolean value:

def assert_(cond): assert cond

values = [ range(10) ] 
expected_values = [ range(10) ]

map (lambda x: assert_(x[0] == x[1]) ,zip( [ run_function(i) for i in values ], expected_values))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.