I've defined a few custom exceptions for one of my projects. Much in the way one can use a standard Python exception (e.g. ZeroDivisionError) without needing to import anything, is there any way I could set up my project to have my custom exceptions exposed to all of the files in one of my packages?
1 Answer
Python puts all of the builtin exception types into the builtins module. So, no matter where you evaluate ZeroDivisionError, it can be found.1
Your exceptions aren't in builtins, they're in whatever module you defined them in. So, they have to be accessed as mymodule.MyError, or imported with something like from mymodule import MyError.
Also, as N. Chauhan points out in a comment, you rarely need more than a handful of public exception types—often only one. You might have 30 different error types that matter internally, but your users probably only care about 1 or 2 different kinds of errors, so you can make your 30 types all subclasses of 1 or 2 base classes, and your users only have to import those.
Could you do the same trick? Yes, and it's actually pretty easy2—but it's almost always a bad idea.
It might sound like that would be handy for interactive programming at the REPL—but it isn't needed there. Just add new stuff into the current (__main__) module, and it's just as accessible as if it were in builtins, right? And Python provides syntactic sugar for doing that. In fact, that's exactly what from mymodule import MyError does: it adds MyError into the current module's globals.
And for non-interactive programming, putting stuff into builtins makes your code confusing and hard to read.
If I see MyError in some code, and from mymodule import MyError at the top, it's obvious where it came from. If I don't, then there's no way to figure out where MyError came from except by exhaustively searching the entire codebase and all site-packages modules imported anywhere.
And it's even harder for IDEs and other tools that help you write and navigate your code. If I hover over MyError in PyCharm, and there's a from mymodule import MyError at the top, PyCharm immediately knows where it came from and can show a nice tooltip with whatever information seems useful. I can right-click it and it can jump to the definition of MyError. If I enable static type checking, it knows what a MyError is and can verify that it's a subclass of Exception. And so on. But without that import, there is no way PyCharm could possibly know what MyError means.
1. When you evaluate ZeroDivisionError, the oversimplified version of the way it works is that if it's not a local or free variable, Python looks for it in globals, and, if it's not there, in builtins. (For a deeper explanation, see the eval and exec docs, and for full details, see Resolution of names.)
2. How do you do it? You can substitute a different builtins module into globals that happens to include your extra stuff, but the really easy way is to just import builtins and just add new stuff into it, like builtins.MyError = MyError.
builtinsmodule. However, it is not possible nor desirable to add custom classes to that module.from myexceptions import *at the beginning of your files.connectionError,RequestErrorandWebsiteErrorshould be combined into one error, sayHTTPError. If you manage to define only one error, you're left to choose whether to import it into each file or to define it again in each file.