2

I place many checks of the program state, whose failure would indicate a bug in the code. In such cases, I'd love to use assert condition simply because it reads nicer than if not condition: raise MyException.

Using assert instead of raise has two problems.

  1. assert does not allow to specify the exception to be raised, so catching it later becomes hard (catching AssertionError may catch too much).

  2. assert is disabled when -O flag is passed to the interpreter.

In my environment any bug in the code requires that I discard any results until the bug is identified and fixed. Therefore, there's no point catching exceptions raised by the above checks. Thus, problem #1 is irrelevant in my situation.

Problem #2 is serious. I want my checks to remain in production code, since correctness is far more important than performance in my environment. Few people use -O flag today; but one day I or someone else may prefer to use it (e.g., to suppress code behind if __debug__, or because -O might actually optimize code in the future). Since all my assert statements must remain active in the production code, I'll need to replace all assert statements with something else. Is there any way to force assert to stay despite the -O flag?

By the way, I'm planning to customize the behavior of assert by printing variable values from the line that caused the assert to fail. I think I can do it by replacing sys.excepthook with my own function that catches AssertionError, reads the traceback, finds the relevant source code, prints the variables from the relevant line, and then reraises the exception. If anyone sees a problem with that, please let me know.

max
  • 49,282
  • 56
  • 208
  • 355
  • I assume you're using `assert` to identify catastrophic failure conditions, and not just ordinary exception conditions? – Robert Harvey Mar 29 '12 at 16:27
  • Precisely. I'm still using proper exceptions to catch unusual inputs, etc - I'm only using `assert` to catch mistakes in the code. In my particular environment, any mistake in the code is considered a catastrophic failure (production code is not allowed to run if it contains any known bugs, however minor). – max Mar 29 '12 at 16:30
  • It doesn't look good. Removing assertions is apparently a "feature" of the -O switch. http://stackoverflow.com/q/1273211/102937 – Robert Harvey Mar 29 '12 at 16:44
  • I updated the question to emphasize that I'm not concerned with the future behavior of the -O flag. I'm just concerned with the possibility that anyone (today or in the future) may want to use `-O` for whatever reason. If so, they'll break the intended behavior of the code (specifically, error checking). – max Mar 29 '12 at 16:46
  • @RobertHarvey I am afraid you are right :( However, there might be a reasonably reliable safe monkey patch that would protect `assert` statements somehow. Even if it simply exits if the interpreter is called with -O flag, and warns the user, I'd live with that.. not ideal, of course.. – max Mar 29 '12 at 16:49
  • Assuming that your environment is configuration-controlled in some way (a reasonable assumption, given the critical nature of your code), couldn't you just require your users to refrain from using the -O switch, or provide a stub executable that calls the Python interpreter without the -O switch? – Robert Harvey Mar 29 '12 at 16:51
  • Each user runs the code themselves, but it's a good suggestion to provide some configuration wrapper around the way they call the interpreter. – max Mar 29 '12 at 17:05
  • 1
    Just don't use assertions if they aren't what you need. Be explicit, the `assert` statement carries those "I may or may not be run at all" semantics. If you just want to save typing on error conditions, create a function `def require(cond, msg): if not cond: raise MyException(msg)`. –  Mar 29 '12 at 17:08
  • @RobertHarvey @delnan: Thanks, I'm persuaded that I've been trying to use `assert` differently than what the language intended it to.. I'll use something like `require` instead for my purposes. Should I delete the question? – max Mar 29 '12 at 17:42
  • @Delnan can write an answer. Can't you Delnan? :) I think this question has value for future readers. – Robert Harvey Mar 29 '12 at 17:43

1 Answers1

7

Just don't use assertions if they aren't what you need. Instead be explicit that you'll throw this exception if some condition is violated. The assert statement always carries a "I may or may not be run at all" side. It's less hacky, less astonishing, less likely to break in the future, and does not require you to prevent users from adding -O.

If you just want to save typing, you can do so. Create a function like this (a more specific name is highly recommended) and use it instead of assert:

def require(cond, msg):
    if not cond:
        raise MyException(msg)