Unusual import of a class in Python
Question:
There is a file exceptions.py
present in kubernetes.client
folder where ApiException
class is defined. So I can write the following line in my own file say myfile.py
and use the ApiException
for raising exception.
some_folder.myfile.py code snippet:
from kubernetes.client.exceptions import ApiException
.....
.....
try:
.....
except ApiException as e:
.....
That is fine.
Also in rest.py
present in kubernetes.client
folder is importing the same class ApiException
and raising some exception.
kubernetes.client.rest.py code snippet:
from kubernetes.client.exceptions import ApiException
.....
.....
if not 200 <= r.status <= 299:
raise ApiException(http_resp=r)
That is also fine. But I am pretty much confused to see the below things as ApiException
is imported from kubernetes.client.rest
in some_file.py
file (see below), not from kubernetes.client.exceptions
where actual class definition for ApiException
is present.
some_folder.some_file.py code snippet:
from kubernetes.client.rest import ApiException
.....
.....
try:
.....
except ApiException as e:
.....
The above code is working but I am really surprised. Can somebody explain me what is happening here. Sorry I am new to Python.
Note:
- ApiException class is not defined in
kubernetes.client.rest
, it is only defined in kubernetes.client.exceptions
- I have searched many articles at online but did not get much information.
Answers:
The name ApiException
is also defined in kubernetes.client.rest
, because it’s been imported there. kubernetes.client.rest
is using it, so it exists there. Any name that exists at the top level of a module is an attribute of that module and can be imported from elsewhere. It doesn’t matter how that name got to be defined there.
Arguably the class should be imported from its canonical location where it has been defined, but it doesn’t have to be. some_folder.some_file.py
might not know where the exception has been originally defined, if it only interacts with kubernetes.client.rest
and just needs to catch exceptions raised there.
You will often see this technique used in __init__.py
files to simply re-export some classes defined in submodules under a simpler name, e.g.:
# foo/__init__.py
from .submodule import Foo
from .othermodule import Bar
This allows users of foo
to from foo import Foo
, instead of having to do from foo.submodule import Foo
, but it still keeps the implementation of foo
clean and separated into multiple files.
There is a file exceptions.py
present in kubernetes.client
folder where ApiException
class is defined. So I can write the following line in my own file say myfile.py
and use the ApiException
for raising exception.
some_folder.myfile.py code snippet:
from kubernetes.client.exceptions import ApiException
.....
.....
try:
.....
except ApiException as e:
.....
That is fine.
Also in rest.py
present in kubernetes.client
folder is importing the same class ApiException
and raising some exception.
kubernetes.client.rest.py code snippet:
from kubernetes.client.exceptions import ApiException
.....
.....
if not 200 <= r.status <= 299:
raise ApiException(http_resp=r)
That is also fine. But I am pretty much confused to see the below things as ApiException
is imported from kubernetes.client.rest
in some_file.py
file (see below), not from kubernetes.client.exceptions
where actual class definition for ApiException
is present.
some_folder.some_file.py code snippet:
from kubernetes.client.rest import ApiException
.....
.....
try:
.....
except ApiException as e:
.....
The above code is working but I am really surprised. Can somebody explain me what is happening here. Sorry I am new to Python.
Note:
- ApiException class is not defined in
kubernetes.client.rest
, it is only defined inkubernetes.client.exceptions
- I have searched many articles at online but did not get much information.
The name ApiException
is also defined in kubernetes.client.rest
, because it’s been imported there. kubernetes.client.rest
is using it, so it exists there. Any name that exists at the top level of a module is an attribute of that module and can be imported from elsewhere. It doesn’t matter how that name got to be defined there.
Arguably the class should be imported from its canonical location where it has been defined, but it doesn’t have to be. some_folder.some_file.py
might not know where the exception has been originally defined, if it only interacts with kubernetes.client.rest
and just needs to catch exceptions raised there.
You will often see this technique used in __init__.py
files to simply re-export some classes defined in submodules under a simpler name, e.g.:
# foo/__init__.py
from .submodule import Foo
from .othermodule import Bar
This allows users of foo
to from foo import Foo
, instead of having to do from foo.submodule import Foo
, but it still keeps the implementation of foo
clean and separated into multiple files.