Criei algum código Python para usar uma classe externa de sua classe interna , com base em uma boa ideia de outra resposta para esta pergunta. Acho que é curto, simples e fácil de entender.
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}
O código principal, "pronto para produção" (sem comentários, etc.). Lembre-se de substituir todos os valores entre colchetes angulares (por exemplo <x>
) pelo valor desejado.
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>}
Explicação de como esse método funciona (as etapas básicas):
Crie uma função chamada _subclass_container
para atuar como um invólucro para acessar a variável self
, uma referência à classe de nível superior (do código executado dentro da função).
Crie uma variável chamada _parent_class
que é uma referência à variável self
desta função, que as subclasses de _subclass_container
podem acessar (evita conflitos de nome com outras self
variáveis nas subclasses).
Retorne a subclasse / subclasse como um dicionário / lista para que o código que chama a _subclass_container
função possa acessar as subclasses internas.
Na __init__
função dentro da classe de nível superior (ou onde mais necessário), receba as subclasses retornadas da função _subclass_container
na variável subclasses
.
Atribua subclasses armazenadas na subclasses
variável a atributos da classe de nível superior.
Algumas dicas para tornar os cenários mais fáceis:
Tornando o código para atribuir as subclasses à classe de nível superior mais fácil de copiar e ser usado em classes derivadas da classe de nível superior que têm sua __init__
função alterada:
Insira antes da linha 12 no código principal:
def _subclass_init(self):
Em seguida, insira nesta função as linhas 5-6 (do código principal) e substitua as linhas 4-7 pelo seguinte código:
self._subclass_init(self)
Tornar possível a atribuição de subclasses à classe de nível superior quando houver muitas / quantidades desconhecidas de subclasses.
Substitua a linha 6 pelo seguinte código:
for subclass_name in list(subclasses.keys()):
setattr(self, subclass_name, subclasses[subclass_name])
Cenário de exemplo de onde esta solução seria útil e onde o nome da classe de nível superior deveria ser impossível de obter:
Uma classe chamada "a" ( class a:
) é criada. Ele tem subclasses que precisam acessá-lo (o pai). Uma subclasse é chamada de "x1". Nesta subclasse, o código a.run_func()
é executado.
Em seguida, outra classe, denominada "b", é criada, derivada da classe "a" ( class b(a):
). Depois disso, algum código é executado b.x1()
(chamando a subfunção "x1" de b, uma subclasse derivada). Esta função é executada a.run_func()
, chamando a função "run_func" da classe "a", não a função "run_func" de seu pai, "b" (como deveria), porque a função que foi definida na classe "a" é definida como referência para a função da classe "a", visto que era sua mãe.
Isso causaria problemas (por exemplo, se a função a.run_func
foi excluída) e a única solução sem reescrever o código na classe a.x1
seria redefinir a subclasse x1
com o código atualizado para todas as classes derivadas da classe "a", o que obviamente seria difícil e não valeria a pena isto.