В папке exceptions.py есть файл kubernetes.client, в котором определен класс ApiException. Поэтому я могу написать следующую строку в своем собственном файле, скажем, myfile.py и использовать ApiException для создания исключения.
Фрагмент кода some_folder.myfile.py:
from kubernetes.client.exceptions import ApiException
.....
.....
try:
.....
except ApiException as e:
.....
Это нормально.
Также в папке rest.py, присутствующей в kubernetes.client, импортируется тот же класс ApiException и возникает некоторое исключение.
Фрагмент кода kubernetes.client.rest.py:
from kubernetes.client.exceptions import ApiException
.....
.....
if not 200 <= r.status <= 299:
raise ApiException(http_resp=r)
Это тоже хорошо. Но я очень смущен, увидев приведенные ниже вещи, поскольку ApiException импортируется из kubernetes.client.rest в файл some_file.py (см. Ниже), а не из kubernetes.client.exceptions, где присутствует фактическое определение класса для ApiException.
Фрагмент кода some_folder.some_file.py:
from kubernetes.client.rest import ApiException
.....
.....
try:
.....
except ApiException as e:
.....
Приведенный выше код работает, но я очень удивлен. Может кто-нибудь объяснить мне, что здесь происходит. Извините, я новичок в Python.
Примечание:
kubernetes.client.rest
, он определен только в kubernetes.client.exceptions
Имя ApiException также определено в kubernetes.client.rest, потому что оно было импортировано туда. kubernetes.client.rest использует его, значит, он там существует. Любое имя, существующее на верхнем уровне модуля, является атрибутом этого модуля и может быть импортировано откуда угодно. Неважно, как это имя должно быть определено там.
Возможно, класс следует импортировать из его канонического местоположения, где он был определен, но это не обязательно. some_folder.some_file.py может не знать, где изначально было определено исключение, если оно взаимодействует только с kubernetes.client.rest и ему просто нужно перехватывать возникающие там исключения.
Вы часто будете видеть, как этот метод используется в файлах __init__.py для простого повторного экспорта некоторых классов, определенных в подмодулях, под более простым именем, например:
# foo/__init__.py
from .submodule import Foo
from .othermodule import Bar
Это позволяет пользователям foo в from foo import Foo вместо того, чтобы делать from foo.submodule import Foo, но при этом реализация foo остается чистой и разделенной на несколько файлов.