The difference is that when you use from, the __cause__ attribute is set and the message states that the exception was directly caused by. If you omit the from then no __cause__ is set, but the __context__ attribute may be set as well, and the traceback then shows the context as during handling something else happened.
Setting the __context__ happens if you used raise in an exception handler; if you used raise anywhere else no __context__ is set either.
If a __cause__ is set, a __suppress_context__ = True flag is also set on the exception; when __suppress_context__ is set to True, the __context__ is ignored when printing a traceback.
When raising from a exception handler where you don't want to show the context (don't want a during handling another exception happened message), then use raise ... from None to set __suppress_context__ to True.
In other words, Python sets a context on exceptions so you can introspect where an exception was raised, letting you see if another exception was replaced by it. You can also add a cause to an exception, making the traceback explicit about the other exception (use different wording), and the context is ignored (but can still be introspected when debugging). Using raise ... from None lets you suppress the context being printed.
See the raise statement documenation:
The
fromclause is used for exception chaining: if given, the second expression must be another exception class or instance, which will then be attached to the raised exception as the__cause__attribute (which is writable). If the raised exception is not handled, both exceptions will be printed:>>> try: ... print(1 / 0) ... except Exception as exc: ... raise RuntimeError("Something bad happened") from exc ... Traceback (most recent call last): File "<stdin>", line 2, in <module> ZeroDivisionError: int division or modulo by zero The above exception was the direct cause of the following exception: Traceback (most recent call last): File "<stdin>", line 4, in <module> RuntimeError: Something bad happenedA similar mechanism works implicitly if an exception is raised inside an exception handler or a
finallyclause: the previous exception is then attached as the new exception’s__context__attribute:>>> try: ... print(1 / 0) ... except: ... raise RuntimeError("Something bad happened") ... Traceback (most recent call last): File "<stdin>", line 2, in <module> ZeroDivisionError: int division or modulo by zero During handling of the above exception, another exception occurred: Traceback (most recent call last): File "<stdin>", line 4, in <module> RuntimeError: Something bad happened
Also see the Built-in Exceptions documentation for details on the context and cause information attached to exceptions.
Answer from Martijn Pieters on Stack OverflowThe difference is that when you use from, the __cause__ attribute is set and the message states that the exception was directly caused by. If you omit the from then no __cause__ is set, but the __context__ attribute may be set as well, and the traceback then shows the context as during handling something else happened.
Setting the __context__ happens if you used raise in an exception handler; if you used raise anywhere else no __context__ is set either.
If a __cause__ is set, a __suppress_context__ = True flag is also set on the exception; when __suppress_context__ is set to True, the __context__ is ignored when printing a traceback.
When raising from a exception handler where you don't want to show the context (don't want a during handling another exception happened message), then use raise ... from None to set __suppress_context__ to True.
In other words, Python sets a context on exceptions so you can introspect where an exception was raised, letting you see if another exception was replaced by it. You can also add a cause to an exception, making the traceback explicit about the other exception (use different wording), and the context is ignored (but can still be introspected when debugging). Using raise ... from None lets you suppress the context being printed.
See the raise statement documenation:
The
fromclause is used for exception chaining: if given, the second expression must be another exception class or instance, which will then be attached to the raised exception as the__cause__attribute (which is writable). If the raised exception is not handled, both exceptions will be printed:>>> try: ... print(1 / 0) ... except Exception as exc: ... raise RuntimeError("Something bad happened") from exc ... Traceback (most recent call last): File "<stdin>", line 2, in <module> ZeroDivisionError: int division or modulo by zero The above exception was the direct cause of the following exception: Traceback (most recent call last): File "<stdin>", line 4, in <module> RuntimeError: Something bad happenedA similar mechanism works implicitly if an exception is raised inside an exception handler or a
finallyclause: the previous exception is then attached as the new exception’s__context__attribute:>>> try: ... print(1 / 0) ... except: ... raise RuntimeError("Something bad happened") ... Traceback (most recent call last): File "<stdin>", line 2, in <module> ZeroDivisionError: int division or modulo by zero During handling of the above exception, another exception occurred: Traceback (most recent call last): File "<stdin>", line 4, in <module> RuntimeError: Something bad happened
Also see the Built-in Exceptions documentation for details on the context and cause information attached to exceptions.
In 2005, PEP 3134, Exception Chaining and Embedded Tracebacks introduced exception chaining:
- implicit chaining with explicit
raise EXCEPTIONor implicit raise (__context__attribute); - explicit chaining with explicit
raise EXCEPTION from CAUSE(__cause__attribute).
Motivation
During the handling of one exception (exception A), it is possible that another exception (exception B) may occur. In today’s Python (version 2.4), if this happens, exception B is propagated outward and exception A is lost. In order to debug the problem, it is useful to know about both exceptions. The
__context__attribute retains this information automatically.Sometimes it can be useful for an exception handler to intentionally re-raise an exception, either to provide extra information or to translate an exception to another type. The
__cause__attribute provides an explicit way to record the direct cause of an exception.[…]
Implicit Exception Chaining
Here is an example to illustrate the
__context__attribute:def compute(a, b): try: a/b except Exception, exc: log(exc) def log(exc): file = open('logfile.txt') # oops, forgot the 'w' print >>file, exc file.close()Calling
compute(0, 0)causes aZeroDivisionError. Thecompute()function catches this exception and callslog(exc), but thelog()function also raises an exception when it tries to write to a file that wasn’t opened for writing.In today’s Python, the caller of
compute()gets thrown anIOError. TheZeroDivisionErroris lost. With the proposed change, the instance ofIOErrorhas an additional__context__attribute that retains theZeroDivisionError.[…]
Explicit Exception Chaining
The
__cause__attribute on exception objects is always initialized toNone. It is set by a new form of theraisestatement:raise EXCEPTION from CAUSEwhich is equivalent to:
exc = EXCEPTION exc.__cause__ = CAUSE raise excIn the following example, a database provides implementations for a few different kinds of storage, with file storage as one kind. The database designer wants errors to propagate as
DatabaseErrorobjects so that the client doesn’t have to be aware of the storage-specific details, but doesn’t want to lose the underlying error information.class DatabaseError(Exception): pass class FileDatabase(Database): def __init__(self, filename): try: self.file = open(filename) except IOError, exc: raise DatabaseError('failed to open') from excIf the call to
open()raises an exception, the problem will be reported as aDatabaseError, with a__cause__attribute that reveals theIOErroras the original cause.Enhanced Reporting
The default exception handler will be modified to report chained exceptions. The chain of exceptions is traversed by following the
__cause__and__context__attributes, with__cause__taking priority. In keeping with the chronological order of tracebacks, the most recently raised exception is displayed last; that is, the display begins with the description of the innermost exception and backs up the chain to the outermost exception. The tracebacks are formatted as usual, with one of the lines:The above exception was the direct cause of the following exception:
or
During handling of the above exception, another exception occurred:
between tracebacks, depending whether they are linked by
__cause__or__context__respectively. Here is a sketch of the procedure:def print_chain(exc): if exc.__cause__: print_chain(exc.__cause__) print '\nThe above exception was the direct cause...' elif exc.__context__: print_chain(exc.__context__) print '\nDuring handling of the above exception, ...' print_exc(exc)[…]
In 2012, PEP 415, Implement Context Suppression with Exception Attributes introduced exception context suppression with explicit raise EXCEPTION from None (__suppress_context__ attribute).
Proposal
A new attribute on
BaseException,__suppress_context__, will be introduced. Whenever__cause__is set,__suppress_context__will be set toTrue. In particular,raise exc from causesyntax will setexc.__suppress_context__toTrue. Exception printing code will check for that attribute to determine whether context and cause will be printed.__cause__will return to its original purpose and values.There is precedence for
__suppress_context__with theprint_line_and_fileexception attribute.To summarize,
raise exc from causewill be equivalent to:exc.__cause__ = cause raise excwhere
exc.__cause__ = causeimplicitly setsexc.__suppress_context__.
So in PEP 415, the sketch of the procedure given in PEP 3134 for the default exception handler (its job is to report exceptions) becomes the following:
def print_chain(exc):
if exc.__cause__:
print_chain(exc.__cause__)
print '\nThe above exception was the direct cause...'
elif exc.__context__ and not exc.__suppress_context__:
print_chain(exc.__context__)
print '\nDuring handling of the above exception, ...'
print_exc(exc)
When should I use raise X from None in Python?
How do I re-raise the current exception in Python?
What is the difference between raise X from Y and just raise X in Python?
There is no "invalid argument" or "null pointer" built-in exception in Python. Instead, most functions raise TypeError (invalid type such as NoneType) or ValueError (correct type, but the value is outside of the accepted domain).
If your function requires an object of a particular class and gets None instead, it should probably raise TypeError as you pointed out. In this case, you should check for None explicitly, though, since an object of correct type may evaluate to boolean False if it implements __nonzero__/__bool__:
if MyArg2 is None:
raise TypeError
Python docs:
TypeErrorpython2 / python3ValueErrorpython2 / python3
As others have noted, TypeError or ValueError would be natural. If it doesn't seem specific enough, you could subclass whichever of the two exceptions is a better fit. This allows consistent handling of invalid arguments for a broad class of functions while also giving you more detail for the particular function.
Hi there,
I’ve recently been trying to write type safe code by enforcing strict mypy checking.
In doing so, I’ve realised some holes in my general code style and want to make it A) consistent throughout the code base and B) do it the most pythonic way.
I’m using this with c extension APIs so I’m just going to make up some very contrived examples
Let’s say we have a function which fetches an instance of an object
def get_item(name: str) -> ItemClass:
if item := api.get_item({‘name’: name}):
return itemI have to try retrieve the object- at this point I may have the object or I may have “None” or “False” depending on the call.
Using mypy, it requires a return call at the end of the function (a good thing imo). So naturally I add “return None”
But now of course I have to change my function signature.
def get_item(name: str) -> Optional[ItemClass]:
if item := api.get_item({‘name’: name}):
return item
return NoneThis works, and it still boils down to me having to check the truthyness of the returned value from my function, but I’m wondering if the more pythonic thing to do would be to raise an exception instead of returning None.
What is the communities feeling of best practice? And especially how it ties into writing code that is robust
Many thanks for your time
I would definitely go for the return None option. Raising an exception may increase readability (although I doubt it) on the function itself, but handling it is messier. If you return None, from the caller function you can do the following:
citation = check_case_citation("Case 145/80")
if citation:
# Do something
else:
# Do something else
while, if you raise an exception, you would have something like
try:
citation = check_case_citation("Case 145/80")
# Do something
except NoParagraphNumberError:
# Do something else
The third option, as suggested by Mathias Ettinger, would be to do
try:
citation = check_case_citation("Case 145/80")
except NoParagraphNumberError:
# Do something else
else:
# Do something
I don't know about you, but to me the first alternative looks the cleanest and most straightforward...
I would go for the second option, raising an error and then handle it in the calling environment with the try-except construct. I say this because in contrast to other programming languages like C, in Python the EAFP (it’s easier to ask for forgiveness than permission) approach is the idiomatic way of writing Python code.
As Brett Canon explains in this article "you should just do what you expect to work and if an exception might be thrown from the operation then catch it and deal with that fact".
Though this is probably more of a CS question than a Python specific question, I'm more familiar with py in general. So let's say I have a function that makes an external API call, and returns a list from a parsed JSON response object. Would it be better to raise parameter problems like a malformed url or a status code error ONLY in that function, returning an empty list (or None) to that it evaluates to 'false' but doesn't throw if a call to a sequence is made to the response... <inhales> or raise a value error if nothing is found, leaving the handling up to the caller?
Usually API's return a json with the key error and details in it. Thanks to this any script that uses it it can just check if data.get('error'): and log or ignore the details or it.
This is very consistent with Promises and Observables in JavaScript
........................... EDIT ............................
Check this reply I made a few days ago, I implemented a decorator that handles that for you. With it, in case of error, you can raise the exception and just return the details inside the error key.
I would make the function raise one (of multiple) exception for the following reasons:
-
What if the function is supposed to return None in certain cases?
-
Exceptions, if used properly, contains more information and can actually describe what went wrong.
-
Multiple exceptions can be added, allowing for more granularity when handling them.
-
Raising exceptions in multiple places can allow for more narrowly defined functionality, which can be useful in unit tests.
Say you're making the API wrapper function public, so that others can use it. Would understanding if, and then what, went wrong be easier to understand for the end user if the functions returns None instead of an exception?
It's really a matter of semantics. What does foo = latestpdf(d) mean?
Is it perfectly reasonable that there's no latest file? Then sure, just return None.
Are you expecting to always find a latest file? Raise an exception. And yes, re-raising a more appropriate exception is fine.
If this is just a general function that's supposed to apply to any directory, I'd do the former and return None. If the directory is, e.g., meant to be a specific data directory that contains an application's known set of files, I'd raise an exception.
I would make a couple suggestions before answering your question as it may answer the question for you.
- Always name your functions descriptive.
latestpdfmeans very little to anyone but looking over your functionlatestpdf()gets the latest pdf. I would suggest that you name itgetLatestPdfFromFolder(folder).
As soon as I did this it became clear what it should return.. If there isn't a pdf raise an exception. But wait there more..
- Keep the functions clearly defined. Since it's not apparent what somefuc is supposed to do and it's not (apparently) obvious how it relates to getting the latest pdf I would suggest you move it out. This makes the code much more readable.
for folder in folders:
try:
latest = getLatestPdfFromFolder(folder)
results = somefuc(latest)
except IOError: pass
Hope this helps!