Hacker News new | ask | show | jobs
by nneonneo 570 days ago
It's worth pointing out that Python's asserts can also be "compiled" away if you use the -O flag (or PYTHONOPTIMIZE=1), which eliminates their runtime cost.

It's also worth pointing out that this is the reason you should *never* put side-effects or security-relevant checks in assert statements. For example, you should never do something like this:

  assert f.read(4) == b"\x89PNG", "Not a PNG file"
  # proceed to read and parse the rest of the file
but rather, you should do

  magic = f.read(4)
  assert magic == b"\x89PNG", "Not a PNG file"
so that your code doesn't suddenly break when someone decides to be clever and use -O.

Also, fun unrelated fact: Python does have something like a preprocessor, although it's rarely used. If you condition on the flag __debug__:

  if __debug__:
    expensive_runtime_check()
and then run Python with -O, the if statement and its body will be entirely deleted from the bytecode - even the `if` check will be deleted. It can be used for including "debug" code in hot code, where the extra flag check itself might be expensive.
1 comments

> but rather, you should do > magic = f.read(4) > assert magic == b"\x89PNG", "Not a PNG file"

If the `assert` compiles out, wouldn’t -O also possibly compile the `read()` out as well given `magic` isn’t used after the assign?

No. Ignoring that Python does not have anywhere near this level of optimisation, read() has side effects so optimising it away would be broken in the general case.

It could be optimised away if all following uses would invalidate (seek, but only with SEEK_SET or SEEK_END) or ignore (pread/pwrite) the file offset, but that seems like an enormous amount of fussy work for what I would guess is little to no payback.

Ah side effects, which Python doesn’t track anyway. Thanks
I don't know the Python rules for thus but the way I understand it from C and C++ is that the read can't be removed by the optimizer because it has (or rather is considered to have) side effects. Iirc every syscall falls into this category.