Я создал некоторый код Python для использования внешнего класса из его внутреннего класса , основанного на хорошей идее из другого ответа на этот вопрос. Я думаю, что это коротко, просто и легко понять.
class higher_level__unknown_irrelevant_name__class:
def __init__(self, ...args...):
...other code...
# Important lines to access sub-classes.
subclasses = self._subclass_container()
self.some_subclass = subclasses["some_subclass"]
del subclasses # Free up variable for other use.
def sub_function(self, ...args...):
...other code...
def _subclass_container(self):
_parent_class = self # Create access to parent class.
class some_subclass:
def __init__(self):
self._parent_class = _parent_class # Easy access from self.
# Optional line, clears variable space, but SHOULD NOT BE USED
# IF THERE ARE MULTIPLE SUBCLASSES as would stop their parent access.
# del _parent_class
class subclass_2:
def __init__(self):
self._parent_class = _parent_class
# Return reference(s) to the subclass(es).
return {"some_subclass": some_subclass, "subclass_2": subclass_2}
Основной код, «продукция готова» (без комментариев и т. Д.). Не забудьте заменить все значения в угловых скобках (например, <x>
) на нужные значения.
class <higher_level_class>:
def __init__(self):
subclasses = self._subclass_container()
self.<sub_class> = subclasses[<sub_class, type string>]
del subclasses
def _subclass_container(self):
_parent_class = self
class <sub_class>:
def __init__(self):
self._parent_class = _parent_class
return {<sub_class, type string>: <sub_class>}
Объяснение того, как работает этот метод (основные шаги):
Создайте функцию с именем _subclass_container
, которая будет действовать как оболочка для доступа к переменной self
, ссылка на класс более высокого уровня (из кода, выполняемого внутри функции).
Создайте переменную с именем _parent_class
, которая является ссылкой на переменную self
этой функции, к которой могут обращаться подклассы _subclass_container
(избегает конфликтов имен с другими переменными self
в подклассах ).
Возвращает подкласс / подклассы в виде словаря / списка, чтобы код, вызывающий функцию _subclass_container
, мог получить доступ к подклассам внутри.
В функции __init__
внутри класса более высокого уровня (или там, где это необходимо) получите возвращенные подклассы из функции _subclass_container
в переменную subclasses
.
Назначение подклассов, хранящихся в переменной subclasses
, атрибутам класса более высокого уровня.
Несколько советов по упрощению сценариев:
Упрощение копирования и использования кода для присвоения подклассов классу более высокого уровня и его использование в классах, производных от класса более высокого уровня, для которых изменена их функция __init__
:
Вставить перед строкой 12 в основной код:
def _subclass_init(self):
Затем вставьте в эту функцию строки 5-6 (основного кода) и замените строки 4-7 следующим кодом:
self._subclass_init(self)
Возможность присвоения подкласса классу более высокого уровня при наличии большого / неизвестного количества подклассов.
Заменить строку 6 следующим кодом:
for subclass_name in list(subclasses.keys()):
setattr(self, subclass_name, subclasses[subclass_name])
Пример сценария, где это решение было бы полезно и где имя класса более высокого уровня было бы невозможно получить:
Создан класс с именем "a" (class a:
). У него есть подклассы, которые должны получить к нему доступ (родитель). Один подкласс называется «x1». В этом подклассе выполняется код a.run_func()
.
Затем создается другой класс с именем "b", полученный из класса "a" (class b(a):
). После этого часть кода запускается b.x1()
(вызывая подфункцию "x1" из b, производный подкласс). Эта функция запускает a.run_func()
, вызывая функцию "run_func" класса "a", not функцию "run_func" ее родителя, "b" (как и должно быть), потому что функция, которая была определена в классе "a" устанавливается ссылка на функцию класса "a", так как она была его родителем.
Это может вызвать проблемы (например, если функция a.run_func
была удалена), и единственным решением без переписывания кода в классе a.x1
будет переопределение подкласса x1
с обновленным кодом для всех классов, полученных из класс "а", который, очевидно, будет сложным и не стоит того.