Calling a function returns a value. Calling print() always returns None. not None is True, so not print("sucess") is True.
In Python, A and B, B is only evaluated if A is truthy. In your code, A is a, and B is print("success")
"assert X, Y" raises AssertionError(Y) if X evaluates to something that is falsey. In your code "assert a and not print("sucess")" is X and "failure" is Y.
In an try/except:
try:
body
except exception_type as excception_info:
exception code
If an exception is raised while the body is executed, control jumps to the except. If the raised exception matches the exception type, the exception code is executed. Information associated with the exception can be passed as an argument (exception_info)
Putting them all together:
If a is True, then then print("success") is called to get the return value of the print() function. The expression "assert a and not print("sucess")" evaluates to True, so the assertion error is not raised.
If a is False, the print() function is not called, and AssertionError("failure") is raised.
If an AssertionError("failure" is raised, the exception code prints the exception info ("failure")