Ive got a boot sequence that needs to check some registry values, they may or may not be present, so each check needs to be wrapped in its own try-except. I try to avoid nesting as I think it can lead to confusion, but what I ended up with was:
reg_a = reg_b = True
reg_a_val = reg_b_val = None
try:
hklm = ConnectRegistry(None, HKLM)
except OSError as err:
# log unable to connect to hivekey
else:
try:
reg_a_val = _get_a_val(hklm)
except OSError as err:
# log failure
reg_a = False
try:
reg_b_val = _get_b_val(hklm)
except OSError as err:
# log failure
reg_b = False
In an attempt to avoid this, I thought maybe setting a flag prior would reduce:
hklm = None
try:
hklm = ConnectRegistry(None, HKLM)
except OSError as err:
# log unable to connect to hivekey
if hklm:
try:
reg_a_val = _get_a_val(hklm)
except OSError as err:
# log failure
reg_a = False
try:
reg_b_val = _get_b_val(hklm)
except OSError as err:
# log failure
reg_b = False
But I then realized its the same depth as just putting them in the else
block.
So which would be preferred? If neither, is there an alternative when subsequent try-except blocks must be used while accessing a variable from a preceding try-except?
Edit:
Another form would be to exclude the else block and roll the nesting into the try-except, essentially implying an "else" should ConnectRegistry
not fail:
reg_a_val = reg_b_val = None
try:
with ConnectRegistry(None, HKLM) as hklm:
try:
reg_a_val = _get_a_val(hklm)
except OSError as err:
# log failure
try:
reg_b_val = _get_b_val(hklm)
except OSError as err:
# log failure
except OSError as err:
# log unable to connect to hivekey
This is done because the outer try-except would need to log failure to even access the hiveroot, whereas the inner try-excepts may or may not fail, but we need to continue even if one does fail. Therefore, the question becomes, is nesting a try-except always considered bad practice, or is a case like this perfectly clear?
reg_a, reg_b = get_reg_a_and_b()
. I know this doesn't quite work because you represent the state of each value via two variables (reg_a
andreg_a_val
) but it can be expanded as necessary. In some cases, the solution could be to keep the various flags in an object, instead of using variables in the local scope. The “real” problem is that you're swallowing the exception fromConnectRegistry()
despite being unable to continue.reg_a is not None
?