160 votes

Comment accéder à une classe externe à partir d'une classe interne ?

J'ai une situation comme ça...

class Outer(object):

    def some_method(self):
        # do something

    class Inner(object):
        def __init__(self):
            self.Outer.some_method()    # <-- this is the line in question

Comment puis-je accéder au Outer de la méthode de la classe Inner classe ?

0 votes

Pourquoi faites-vous cela ? Qu'est-ce qui ne va pas avec de simples relations entre pairs ? Essayez-vous de "dissimuler" quelque chose ?

4 votes

Un exemple de ce scénario pourrait être une classe avec des sous-classes qui doivent accéder à la classe externe, comme d'habitude, mais il faut ensuite créer une autre classe (de premier niveau) dérivée de la première classe. Dans ce cas, les sous-classes de la deuxième classe essaieraient d'accéder au parent en utilisant la méthode suivante self.<original_parent_name> y obtenir la classe originale, pas la nouvelle classe dont ils sont une sous-classe . J'espère que les personnes qui liront ces lignes pourront visualiser ce scénario difficile et comprendre l'intérêt de questions comme celle-ci.

1 votes

Dupliquer à stackoverflow.com/questions/2278426 et il a une belle réponse.

4voto

Edward Points 914

J'ai créé du code Python pour utiliser un fichier classe externe de son classe intérieure sur la base d'une bonne idée d'un autre réponse pour cette question. Je pense qu'elle est courte, simple et facile à comprendre.

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}

Le code principal, "prêt pour la production" (sans commentaires, etc.). N'oubliez pas de remplacer toutes les valeurs entre parenthèses (par ex. <x> ) avec la valeur souhaitée.

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>}

Explication du fonctionnement de cette méthode (les étapes de base) :

  1. Créez une fonction nommée _subclass_container pour servir d'enveloppe à l'accès à la variable self une référence à la classe de niveau supérieur (à partir du code exécuté dans la fonction).

    1. Créez une variable nommée _parent_class qui est une référence à la variable self de cette fonction, que les sous-classes de _subclass_container peut accéder (évite les conflits de noms avec d'autres self dans les sous-classes).

    2. Retourner les sous-classes/sous-classes sous forme de dictionnaire/liste afin que le code appelant la fonction _subclass_container peut accéder aux sous-classes qu'elle contient.

  2. Dans le __init__ à l'intérieur de la classe de niveau supérieur (ou à tout autre endroit nécessaire), recevoir les sous-classes retournées par la fonction _subclass_container dans la variable subclasses .

  3. Affecter les sous-classes stockées dans le subclasses aux attributs de la classe de niveau supérieur.

Quelques conseils pour faciliter les scénarios :

En rendant le code permettant d'affecter les sous-classes à la classe de niveau supérieur plus facile à copier et à utiliser dans les classes dérivées de la classe de niveau supérieur qui ont leurs propres classes de niveau supérieur. __init__ la fonction a changé :

Insérer avant la ligne 12 dans le code principal :

def _subclass_init(self):

Insérez ensuite dans cette fonction les lignes 5-6 (du code principal) et remplacez les lignes 4-7 par le code suivant :

self._subclass_init(self)

Rendre possible l'assignation d'une sous-classe à la classe de niveau supérieur lorsqu'il y a beaucoup/une quantité inconnue de sous-classes.

Remplacez la ligne 6 par le code suivant :

for subclass_name in list(subclasses.keys()):
    setattr(self, subclass_name, subclasses[subclass_name])

Exemple de scénario où cette solution serait utile et où le nom de la classe de niveau supérieur devrait être impossible à obtenir :

Une classe, nommée "a" ( class a: ) est créé. Des sous-classes doivent y accéder (le parent). Une sous-classe est appelée "x1". Dans cette sous-classe, le code a.run_func() est exécuté.

Ensuite, une autre classe, nommée "b" est créée, dérivé de de la classe "a" ( class b(a): ). Après cela, du code s'exécute b.x1() (en appelant la sous-fonction "x1" de b, une sous-classe dérivée). Cette fonction exécute a.run_func() en appelant la fonction "run_func" de la classe "a", no la fonction "run_func" de son parent, "b" (comme il se doit), parce que la fonction qui a été définie dans la classe "a" est configurée pour se référer à la fonction de la classe "a", puisque c'était son parent.

Cela poserait des problèmes (par exemple, si la fonction a.run_func a été supprimé) et la seule solution sans réécrire le code dans la classe a.x1 serait de redéfinir la sous-classe x1 avec un code mis à jour pour toutes les classes dérivées de la classe "a", ce qui serait évidemment difficile et n'en vaut pas la peine.

4voto

grundic Points 171

Vous pouvez facilement accéder à la classe externe en utilisant la métaclasse : après la création de la classe externe, vérifiez la dictée de ses attributs pour toute classe (ou appliquez toute logique dont vous avez besoin - mon exemple est juste trivial) et définissez les valeurs correspondantes :

import six
import inspect

# helper method from `peewee` project to add metaclass
_METACLASS_ = '_metaclass_helper_'
def with_metaclass(meta, base=object):
    return meta(_METACLASS_, (base,), {})

class OuterMeta(type):
    def __new__(mcs, name, parents, dct):
        cls = super(OuterMeta, mcs).__new__(mcs, name, parents, dct)
        for klass in dct.values():
            if inspect.isclass(klass):
                print("Setting outer of '%s' to '%s'" % (klass, cls))
                klass.outer = cls

        return cls

# @six.add_metaclass(OuterMeta) -- this is alternative to `with_metaclass`
class Outer(with_metaclass(OuterMeta)):
    def foo(self):
        return "I'm outer class!"

    class Inner(object):
        outer = None  # <-- by default it's None

        def bar(self):
            return "I'm inner class"

print(Outer.Inner.outer)
>>> <class '__main__.Outer'>
assert isinstance(Outer.Inner.outer(), Outer)

print(Outer().foo())
>>> I'm outer class!
print(Outer.Inner.outer().foo())
>>> I'm outer class!
print(Outer.Inner().outer().foo())
>>> I'm outer class!
print(Outer.Inner().bar())
>>> I'm inner class!

En utilisant cette approche, vous pouvez facilement lier et référencer deux classes entre elles.

3voto

CIRCLE Points 675

Voulez-vous utiliser l'héritage, plutôt que d'imbriquer les classes comme ceci ? Ce que vous faites n'a pas beaucoup de sens en Python.

Vous pouvez accéder à la Outer d'une méthode quelconque en faisant simplement référence à Outer.some_method dans les méthodes de la classe interne, mais cela ne fonctionnera pas comme vous l'attendez. Par exemple, si vous essayez ceci :

class Outer(object):

    def some_method(self):
        # do something

    class Inner(object):
        def __init__(self):
            Outer.some_method()

...vous obtiendrez une TypeError lors de l'initialisation d'un fichier Inner car Outer.some_method s'attend à recevoir un Outer comme premier argument. (Dans l'exemple ci-dessus, vous essayez essentiellement d'appeler some_method comme une méthode de classe de Outer .)

3voto

tsnorri Points 522

Une autre possibilité :

class _Outer (object):
    # Define your static methods here, e.g.
    @staticmethod
    def subclassRef ():
        return Outer

class Outer (_Outer):
    class Inner (object):
        def outer (self):
            return _Outer

        def doSomething (self):
            outer = self.outer ()
            # Call your static mehthods.
            cls = outer.subclassRef ()
            return cls ()

2voto

mits_v Points 21

Ce que nous pouvons faire est de passer la variable self de Extérieur à l'intérieur de la classe interne en tant qu'argument de classe et sous Outer init initialiser la classe interne avec Outer self passé dans Inner.

class Outer:
    def __init__(self):
        self.somevalue=91
        self.Inner=self.Inner(self)
    def SomeMethod(self):
        print('This is Something from Outer Class')

    class Inner:
        def __init__(self,Outer)
            self.SomeMethod=Outer.SomeMethod
            self.somevalue=Outer.somevalue

        def SomeAnotherMethod(self):
            print(self.somevalue)
            self.SomeMethod()        

>>>f=Outer()
>>>f.Inner.SomeAnotherMethod() 
91
This is Something from Outer Class

Après avoir exécuté cette fonction, cela fonctionne

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X