I’d like to add a small clarification. I posted this to the Ideas, the category for people who “would like to change something in Python”. I realized it was moved to Python help for some reason. I do appreciate all feedback, but I was not asking for help.
It possibly seems a moderator thought mentoring in debugging might help.
“That’s fine” is one way of putting it. Let me rephrase it though. If you have a use-case that is contrary to the vast majority of Python users, that’s fine. You still have a use-case, but you are HIGHLY unlikely to see syntax for what you’re looking for, and will have to content yourself with the longhand way of writing it.
Uncommon use-cases are handled with more verbose, and usually custom, code.
Most likely because a moderator deemed it a non-viable idea, and much more productive for it to be a Python help question. Which I would agree with; you’re far more likely to get useful help of the form “how can I do this better?” than to see your original proposal get implemented.
How could you know that? It is not possible to see in use something that does not exist.
Your request runs contrary to the design philosophy of Python, and most Python programmers work with that philosophy, not against it.
Like I said, uncommon use-cases aren’t a problem, they just aren’t as likely to get any sort of language support. And you clearly can achieve what you want, albeit with more code than you were hoping for.
The often used dict.get(key, default)
does something very similar, it tries to return a value the user asks for and if that is not possible it returns the replacement value. Would you say it is contrary too? And there is also other similarity, .get
is not needed at all, one can write try-except KeyError
.
Errors should never pass silently.
Unless explicitly silenced.
Errors should never pass silently.
Unless explicitly silenced.
Did you read my original post? The errors are explicitly silenced. What’s the problem?
Many years ago there was a much more general proposal (PEP-463 – Exception-catching expressions) that was rejected, but there was a regular discussion.
I’d like to ask the moderator to kindly move my proposal (the first post of this thread) back to the “Ideas” or to explain why it does not fullfil the requirements.
So far in this thread, there has not been a single other person wanting this. You’re looking at something that wants custom code, NOT a language feature.
No sir, not at all. I wouldn’t propose something so insane. That must be a misunderstanding. I have an suggestion to add an optional feature to string formatting and was looking for feedback. It is clearly negative so far, but only opinion based IMO.
Unless e.g. a new conversion specifier is explicitly (i.e. deliberately) used in string formatting specification, everything stays as usual, of course.
# regular code (may cause an exception, undef var or lookup error)
print(f"mode = {mode}, state = {state[mode].name})
# my proposal (will always print)
print(f"mode = {mode!e}, state = {state[mode].name!e})
And the larger picture:
try:
# lines of code
# if an error occurs here, mode is undef
mode = ...
# more lines of code
state[mode] = ...
# even more lines of code
except Exception:
# compared to the standard, this print won't make a problem,
# in the worst case the information will be of little use
print(f"DEBUG: {mode!e}, state = {state[mode].name!e}")
raise
Because it is in a wrong category perhaps?
For what it’s worth, my weird little class at the top will do what you want without making a change to the language or, for the most part, your code.
I do think you’re underestimating how large of a change this would be to the language. Right now, the !s
and !r
are operations that apply to the result of an expression; they don’t wrap the expression execution, which would be needed to suppress an exception. I don’t know how invasive your proposed change would end up being, but I also strongly suspect that one argument against it would be that as a single character there’s no way to know if somebody wants <N/A>
, the exception repr, or any other fallback value.
Assuming your most recent example is in fact what you’re doing, I think this is a use for logging:
logger = logging.getLogger("mytool")
# lines of code
# if an error occurs here, mode is undef
mode = ...
logger.debug(f"{mode=}")
# more lines of code
state[mode] = ...
logger.debug(f"state={state[mode].name}")
# even more lines of code
There is the Logging cookbook that you could consult for improving the formatting.
I do use this way of logging too. It is enabled during development and afterward is the log level increased to silence this kind logs. But in addition to that I need the debug data if there are problems in production. I have a lots of functions communicating with external hardware devices. This is not a nice world where everyhing is precisely specified and extensively documented. It happened several times that a code working fine for years suddenly receives input data that was not expected or seemed impossible.
In such cases I would prefer logging only in the case of an error, i.e. in an error handler. Reason 1: not to waste gigabytes for unneeded logs. Reason 2: the error report with the details can be easily sent by email.
That’s a good reason to log aggressively. Everything that’s happening, write it down. Pretend that your program is part of the Apollo flight system and make sure that, even if the spacecraft doesn’t make it to the end of the mission, you can fully recreate what happened, just from the logs. (Okay, that might be a BIT excessive for most use-cases, but you get the idea.)
I have a LOT of debug logging in production code. Yes, I debug in production, because as you say, sometimes it works fine for years and only then has a problem - no matter how much you test, you can’t cope with everything. (Plus, I’m often dealing with other people’s APIs, and there are undocumented quirks to them.) Log EVERYTHING. Don’t hide something behind “<N/A>” when something goes wrong. Log the repr of the object, or if that isn’t useful, some attributes off it.