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.

120voto

Kitlbast Points 81

Vous essayez d'accéder à l'instance de la classe de Outer, depuis l'instance de la classe interne. Il suffit donc d'utiliser la méthode factory pour construire l'instance Inner et lui passer l'instance Outer.

class Outer(object):

    def createInner(self):
        return Outer.Inner(self)

    class Inner(object):
        def __init__(self, outer_instance):
            self.outer_instance = outer_instance
            self.outer_instance.somemethod()

        def inner_method(self):
            self.outer_instance.anothermethod()

0 votes

Incroyable ! Et si vous changez quoi que ce soit dans la classe extérieure, la classe intérieure affiche cette valeur en conséquence !

98voto

Daniel Vassallo Points 142049

Les méthodes d'une classe imbriquée ne peuvent pas accéder directement aux attributs d'instance de la classe externe.

Notez qu'une instance de la classe externe n'existe pas nécessairement même si vous avez créé une instance de la classe interne.

En fait, il est souvent déconseillé d'utiliser des classes imbriquées, car l'imbrication n'implique aucune relation particulière entre les classes intérieures et extérieures.

2 votes

Hmm, Python est plus fringant que Java/C++... voir ma réponse ci-dessous. Si nous coupons les cheveux en quatre, ce qui est généralement le cas, je ne pourrais pas vraiment vous dire si ma "classe imbriquée dans une méthode" compte comme une classe interne. A ce stade, cependant, je dois invoquer le typage en canard : si elle fait tout ce qu'une classe interne pourrait faire... d'un point de vue pythonique, il est probablement temps d'arrêter de couper les cheveux en quatre...

42 votes

Une classe interne implique bien sûr une relation avec la classe externe, généralement liée à la portée d'utilisation implicite de la classe interne ou à un espace de noms organisationnel.

0 votes

Ils le peuvent si vous les définissez comme @Kitlbast l'a suggéré dans une autre réponse. De cette façon, si vous modifiez la valeur d'une variable dans la classe externe et que vous y accédez depuis la classe interne, vous obtiendrez la valeur mise à jour de ladite variable.

41voto

mike rodent Points 482

Peut-être que je suis fou mais cela semble très facile en effet - la chose est de faire votre classe interne à l'intérieur d'une méthode de la classe externe ...

def do_sthg(self):
    ...

def mess_around(self):

    outer_class_self = self

    class Mooble():
        def do_sthg_different(self):
            ...
            outer_class_self.do_sthg()

De plus... "self" n'est utilisé que par convention, donc vous pourriez faire ça :

def do_sthg(self):
    ...

def mess_around(outer_class_self):

    class Mooble():
        def do_sthg_different(self):
            ...
            outer_class_self.do_sthg()

On pourrait objecter que l'on ne peut pas créer cette classe interne à partir de la classe externe... mais ce n'est pas vrai :

class Bumblebee():

    def do_sthg(self):
        print "sthg"

    def give_me_an_inner_class(outer_class_self):

        class Mooble():
            def do_sthg_different(self):
                print "something diff\n"
                outer_class_self.do_sthg()
        return Mooble

puis, quelque part à des kilomètres de là :

blob = Bumblebee().give_me_an_inner_class()()
blob.do_sthg_different()    

même pousser le bateau un peu plus loin et étendre cette classe interne (NB pour obtenir super() pour fonctionner, vous devez changer la signature de la classe de Mooble à class Mooble(object) ).

class InnerBumblebeeWithAddedBounce(Bumblebee().give_me_an_inner_class()):
    def bounce(self):
        print "bounce"

    def do_sthg_different(self):
        super(InnerBumblebeeWithAddedBounce, self).do_sthg_different()
        print "and more different"

ibwab = InnerBumblebeeWithAddedBounce()    
ibwab.bounce()
ibwab.do_sthg_different()

plus tard

mrh1997 a soulevé un point intéressant au sujet de l'héritage non commun des classes internes livrées en utilisant cette technique. Mais il semble que la solution soit assez simple :

class Fatty():
    def do_sthg(self):
        pass

    class InnerFatty(object):
        pass

    def give_me_an_inner_fatty_class(self):
        class ExtendedInnerFatty(Fatty.InnerFatty):
            pass
        return ExtendedInnerFatty

fatty1 = Fatty()
fatty2 = Fatty()

innerFattyClass1 = fatty1.give_me_an_inner_fatty_class()
innerFattyClass2 = fatty2.give_me_an_inner_fatty_class()

print (issubclass(innerFattyClass1, Fatty.InnerFatty))
print (issubclass(innerFattyClass2, Fatty.InnerFatty))

7voto

flying sheep Points 1989

J'ai trouvé este .

Modifié pour répondre à votre question :

class Outer(object):
    def some_method(self):
        # do something

    class _Inner(object):
        def __init__(self, outer):
            outer.some_method()
    def Inner(self):
        return _Inner(self)

Je suis sûr que vous pouvez écrire un décorateur pour ça ou quelque chose comme ça.

liés : Quel est le but des classes internes de Python ?

6voto

tre-x Points 73

Quelques années de retard sur la fête.... mais pour développer @mike rodent J'ai fourni mon propre exemple ci-dessous, qui montre à quel point sa solution est flexible et pourquoi elle devrait être (ou devrait être) une bonne solution. ont a été) la réponse acceptée.

Python 3.7

class Parent():

    def __init__(self, name):
        self.name = name
        self.children = []

    class Inner(object):
        pass

    def Child(self, name):
        parent = self
        class Child(Parent.Inner):
            def __init__(self, name):
                self.name = name
                self.parent = parent
                parent.children.append(self)
        return Child(name)

parent = Parent('Bar')

child1 = parent.Child('Foo')
child2 = parent.Child('World')

print(
    # Getting its first childs name
    child1.name, # From itself
    parent.children[0].name, # From its parent
    # Also works with the second child
    child2.name,
    parent.children[1].name,
    # Go nuts if you want
    child2.parent.children[0].name,
    child1.parent.children[1].name
)

print(
    # Getting the parents name
    parent.name, # From itself
    child1.parent.name, # From its children
    child2.parent.name,
    # Go nuts again if you want
    parent.children[0].parent.name,
    parent.children[1].parent.name,
    # Or insane
    child2.parent.children[0].parent.children[1].parent.name,
    child1.parent.children[1].parent.children[0].parent.name
)

# Second parent? No problem
parent2 = Parent('John')
child3 = parent2.Child('Doe')
child4 = parent2.Child('Appleseed')

print(
    child3.name, parent2.children[0].name,
    child4.name, parent2.children[1].name,
    parent2.name # ....
)

Sortie :

Foo Foo World World Foo World
Bar Bar Bar Bar Bar Bar Bar
Doe Doe Appleseed Appleseed John

Encore une fois, une merveilleuse réponse, bravo à toi Mike !

1 votes

Je m'inquiète de ce qui se passe avec toi pickle cependant, ne se retrouve-t-on pas avec une récursion sans fin ? (Je ne suis pas à une console Python, sinon je le testerais moi-même !)

0 votes

Cette solution est très unique et devrait être évaluée davantage. L'intérêt est d'avoir la même classe Child avec la fonction Child.

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