I made a simple test program to test the functionality of assigning to __debug__ using globals()["__debug__"] = value (__debug__ = value is a SyntaxError). It basically tries to raise an AssertionError and prints if the error was raised and whether or not it was expected. I did this as I ran in to issues with __debug__ changing mid-program.
print("__debug__ is", __debug__)
exp = ["(expected)", "(not expected)"]
if __debug__:
exp = exp[::-1]
try:
assert False
print("No AssertionError", exp[0])
except AssertionError:
print("AssertionError", exp[1])
exp = exp[::-1]
globals()["__debug__"] = not __debug__
print("__debug__ is", __debug__)
try:
assert False
print("No AssertionError", exp[0])
except AssertionError:
print("AssertionError", exp[1])
It produces unexpected results when run from command prompt, with and without the -O flag.
C:\Test>python assert.py
__debug__ is True
AssertionError (expected)
__debug__ is False
AssertionError (not expected)
C:\Test>python -O assert.py
__debug__ is False
No AssertionError (expected)
__debug__ is True
No AssertionError (not expected)
It seems that __debug__ is changing, but assert is not actually checking if it has.
You are not meant to change the value of __debug__
As the note under here states:
Note: The names
None,False,Trueand__debug__cannot be reassigned (assignments to them, even as an attribute name, raiseSyntaxError), so they can be considered “true” constants
The reason this is happening is because __debug__ is not evaluated at runtime, rather the -O command line flag is (At compile time). See also Runtime vs Compile time.
While you can change the value of __debug__ through the hack globals()["__debug__"], it does nothing, as the assert expression1, expression2 doesn't really check for the value of __debug__. Supplying the -O flag assigns False to __debug__ and removes all assert statements. That is to say, assert statements are removed by the -O flag, not the __debug__ variable.
You can see this with dis() from dis. Using the following code:
import dis
dis.dis("assert False")
Without the -O flag (path\to\file>python file.py):
1 0 LOAD_CONST 0 (False)
3 POP_JUMP_IF_TRUE 12
6 LOAD_GLOBAL 0 (AssertionError)
9 RAISE_VARARGS 1
>> 12 LOAD_CONST 1 (None)
15 RETURN_VALUE
With the -O flag (path\to\file>python -O file.py):
1 0 LOAD_CONST 0 (None)
3 RETURN_VALUE
As you can see, the assert statement is essentially removed from the code. Lines 0 to 3 with the -O flag are identical to lines 12 to 15 without. No where does it check for the value of __debug__.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With