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 à la méthode de la classe Outer
à partir de la classe Inner
?
Modifier - Merci pour les réponses. Je conclus que je dois réévaluer la façon dont j'avais conçu cela pour être mis en œuvre et trouver une méthode plus robuste.
Les méthodes d'une classe imbriquée ne peuvent pas accéder directement aux attributs d'instance de la classe externe.
Notez qu'il n'est pas nécessairement le cas qu'une instance de la classe externe existe même lorsque 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 internes et externes.
Vous essayez d'accéder à l'instance de classe Outer, à partir de l'instance de classe interne. Il suffit donc d'utiliser la méthode d'usine pour créer une instance interne et lui passer une instance externe.
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()
peut-être que je suis fou, mais cela semble très facile en effet - le fait est de faire de votre classe intérieure une méthode de la classe extérieure ...
def do_sthg( self ):
...
def messAround( self ):
outerClassSelf = self
class mooble():
def do_sthg_different( self ):
...
outerClassSelf.do_sthg()
De plus ... "self" n'est utilisé que par convention, vous pouvez donc faire ceci:
def do_sthg( self ):
...
def messAround( outerClassSelf ):
class mooble():
def do_sthg_different( self ):
...
outerClassSelf.do_sthg()
On pourrait objecter que vous ne pouvez pas ensuite créer cette classe interne à l'extérieur de la classe externe ... mais ce n'est pas vrai:
class Bumblebee():
def do_sthg( self ):
print "sthg"
def giveMeAnInnerClass( outerClassSelf ):
class mooble():
def do_sthg_different( self ):
print "something diff\n"
outerClassSelf.do_sthg()
return mooble
puis, quelque part à des kilomètres:
blob = Bumblebee().giveMeAnInnerClass()()
blob.do_sthg_different()
même pousser le bateau un peu et étendre cette classe interne (NB pour que super () fonctionne, vous devez changer la signature de classe de mooble en "class mooble (object)"
class InnerBumblebeeWithAddedBounce( Bumblebee().giveMeAnInnerClass() ):
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 à propos de l'héritage non commun des classes internes fournies à l'aide de cette technique. Mais il semble que la solution soit assez simple:
class Fatty():
def do_sthg( self ):
pass
class InnerFatty( object ):
pass
def giveMeAnInnerFattyClass(self):
class ExtendedInnerFatty( Fatty.InnerFatty ):
pass
return ExtendedInnerFatty
fatty1 = Fatty()
fatty2 = Fatty()
innerFattyClass1 = fatty1.giveMeAnInnerFattyClass()
innerFattyClass2 = fatty2.giveMeAnInnerFattyClass()
print ( issubclass( innerFattyClass1, Fatty.InnerFatty ))
print ( issubclass( innerFattyClass2, Fatty.InnerFatty ))
Vous voulez utiliser l'héritage plutôt que d'imbriquer des classes comme celle-ci? Ce que vous faites n'a aucun sens en Python.
Vous pouvez accéder à la méthode de Outer
en référençant simplement Outer.some_method
dans les méthodes de la classe interne, mais cela ne fonctionnera pas comme prévu. 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 objet Inner
, car Outer.some_method
s'attend à recevoir une instance de Outer
comme premier argument. (Dans l'exemple ci-dessus, vous essayez essentiellement d'appeler some_method
comme méthode de classe de Outer
.)
J'ai créé du code Python pour utiliser un classe externe à partir de sa classe interne, basé sur une bonne idée de un autre réponse pour cette question. Je pense que c'est court, 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, "production ready" (sans commentaires, etc.). N'oubliez pas de remplacer toutes les valeurs entre parenthèses (par exemple <x>
) Par 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>}
Créez une fonction nommée _subclass_container
Pour agir comme un wrapper pour accéder à la variable self
, une référence à la classe de niveau supérieur (à partir du code exécuté à l'intérieur de la fonction).
Créez une variable nommée _parent_class
Qui est une référence à la variable self
de cette fonction, à laquelle les sous-classes de _subclass_container
Peuvent accéder (évite les conflits de nom avec les autres self
variables dans les sous-classes).
Renvoie la sous-classe/sous-classes sous forme de dictionnaire/liste afin que le code appelant la fonction _subclass_container
Puisse accéder aux sous-classes à l'intérieur.
Dans la fonction __init__
À l'intérieur de la classe de niveau supérieur (ou partout où cela est nécessaire), recevez les sous-classes renvoyées de la fonction _subclass_container
Dans la variable subclasses
.
Attribuez des sous-classes stockées dans la variable subclasses
aux attributs de la classe de niveau supérieur.
Rendre le code pour 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 leur __init__
fonction modifiée:
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'attribution de sous-classes à la classe de niveau supérieur lorsqu'il existe de nombreuses sous-classes/quantités inconnues.
Remplacez la ligne 6 par le code suivant:
for subclass_name in list(subclasses.keys()):
setattr(self, subclass_name, subclasses[subclass_name])
Une classe, nommée "a" (class a:
) Est créée. Il a des sous-classes qui 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é.
Puis une autre classe, nommée "b" est créée, dérivée de la classe "a" (class b(a):
). Après cela, du code exécute b.x1()
(appelant la sous-fonction "x1" de b, une sous-classe dérivée). Cette fonction exécute a.run_func()
, appelant la fonction "run_func" de la classe "a", pas la fonction "run_func" de son parent , "b" (comme il se doit), car la fonction qui a été définie dans la classe "a" est définie pour faire référence à la fonction de la classe "a", car c'était son parent.
Cela causerait des problèmes (par exemple si la fonction a.run_func
A été supprimée) et la seule solution sans réécrire le code dans la classe a.x1
Serait de redéfinir la sous-classe x1
Avec une mise à jour code pour toutes les classes dérivées de la classe "a", ce qui serait évidemment difficile et n'en vaut pas la peine.
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 ()
Vous pouvez facilement accéder à la classe externe à l'aide de la métaclasse: après la création de la classe externe, vérifiez son attribut dict pour toutes les classes (ou appliquez la logique dont vous avez besoin - la mienne n'est qu'un exemple 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.
Développant la pensée convaincante de @ tsnorri, que la méthode externe peut être une méthode statique :
class Outer(object):
@staticmethod
def some_static_method(self):
# do something
class Inner(object):
def __init__(self):
self.some_static_method() # <-- this will work later
Inner.some_static_method = some_static_method
Maintenant, la ligne en question devrait fonctionner au moment où elle est réellement appelée.
La dernière ligne du code ci-dessus donne à la classe Inner une méthode statique qui est un clone de la méthode statique externe.
Cela profite de deux fonctionnalités Python, que les fonctions sont des objets et la portée est textuelle .
En général, la portée locale fait référence aux noms locaux de la fonction (textuellement) actuelle.
... ou la classe actuelle dans notre cas. Obtient donc "local" à la définition de la classe Outer (Inner
et some_static_method
) peuvent être mentionnés directement dans cette définition.
j'ai trouvé ce .
Ajusté pour répondre à votre question, c'est la réponse:
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 en quelque sorte écrire un décorateur pour ceci ou quelque chose :)
/modifier: n pe