Domanda

Ho una situazione in questo modo ...

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

Come posso accedere il metodo della classe Outer dalla classe Inner?

Modifica - Grazie per le risposte. Sto concludendo che ho bisogno di ri-valutare come avevo progettato questo da attuare e venire con un metodo più robusto.

È stato utile?

Soluzione

I metodi di una classe nidificata non può accedere direttamente l'istanza attributi della classe esterna.

Si noti che non è necessariamente il caso che un'istanza della classe esterna esiste anche quando si è creato un'istanza della classe interna.

In realtà, è spesso consigliato di non utilizzare classi nidificate, poiché l'annidamento non implica alcun rapporto particolare tra le classi interne ed esterne.

Altri suggerimenti

Si sta cercando di accedere a un'istanza di classe di esterno, da istanza di una classe interna. Quindi, basta usare fabbrica metodo per costruire un'istanza interna e passare esempio esterno ad esso.

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()

forse sono pazzo, ma questo sembra molto facile in effetti - la cosa è quello di rendere la vostra classe interna all'interno di un metodo della classe esterna ...

def do_sthg( self ):
    ...

def messAround( self ):

    outerClassSelf = self

    class mooble():
        def do_sthg_different( self ):
            ...
            outerClassSelf.do_sthg()

Inoltre ... "sé" è usato solo per convenzione, in modo che si possa fare questo:

def do_sthg( self ):
    ...

def messAround( outerClassSelf ):

    class mooble():
        def do_sthg_different( self ):
            ...
            outerClassSelf.do_sthg()

Si potrebbe obiettare che non si può quindi creare questa classe interna da fuori classe esterna ... ma questo non è vero:

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

Quindi, da qualche miglia di distanza:

blob = Bumblebee().giveMeAnInnerClass()()
blob.do_sthg_different()    

anche spingere la barca un po 'ed estendere questa classe interna (NB per ottenere super () per lavorare è necessario cambiare la firma classe di Mooble a "classe Mooble (oggetto)"

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()

dopo

mrh1997 sollevato un punto interessante circa l'eredità non comune delle classi interne erogata utilizzando questa tecnica. Ma sembra che la soluzione è piuttosto semplice:

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

Vuoi dire utilizzare l'ereditarietà, piuttosto che le classi di nidificazione come questo? Quello che stai facendo non fa un mucchio di senso in Python.

È possibile accedere some_method del Outer semplicemente riferimento Outer.some_method all'interno dei metodi della classe interna, ma non sta andando a lavorare come ci si aspetta che lo farà. Ad esempio, se si tenta questo:

class Outer(object):

    def some_method(self):
        # do something

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

... si otterrà un TypeError quando l'inizializzazione di un oggetto Inner, perché Outer.some_method si aspetta di ricevere un'istanza Outer come primo argomento. (Nell'esempio precedente, si sta fondamentalmente cercando di chiamare some_method come metodo di classe di Outer.)

Ho creato un po 'di codice Python di usare una classe esterna dalla classe interna , sulla base di una buona idea da un altro rispondere per questa domanda. Penso che sia breve, semplice e facile da capire.

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}

Il codice principale, "pronti per la produzione" (senza commenti, ecc). Ricordarsi di sostituire tutti ogni valore tra parentesi angolari (ad esempio <x>) con il valore desiderato.

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

Spiegazione di come funziona questo metodo (la procedura di base):

  1. Crea una funzione denominata _subclass_container di agire come un wrapper per accedere al self variabile, un riferimento alla classe di livello superiore (da codice in esecuzione all'interno della funzione).

    1. Create una variabile denominata _parent_class che è un riferimento alla self variabili di questa funzione, che le sottoclassi di _subclass_container possono accedere (da evitare conflitti di nome con altre variabili self in sottoclassi).

    2. Torna la sottoclasse / sottoclassi come un dizionario / lista così il codice chiamando la funzione _subclass_container può accedere ai sottoclassi all'interno.

  2. Nella funzione __init__ all'interno della classe di livello più alto (o qualsiasi altra richiesta), ricevere le sottoclassi restituiti dalla funzione _subclass_container nel subclasses variabile.

  3. Assegna sottoclassi memorizzati nella variabile subclasses agli attributi della classe di livello superiore.

Alcuni suggerimenti per rendere più facile scenari:

Portando il codice per assegnare le sottoclassi alla classe livello superiore facile copiare e utilizzare in classi derivate dalla classe di livello superiore che hanno la loro __init__ funzione modificata:

Inserisci prima linea 12 nel codice principale:

    def _subclass_init(self):

Poi inserire in questa funzione linee 5-6 (del codice principale) e sostituire le righe 4-7 con il seguente codice:

        self._subclass_init(self)

Fare sottoclasse l'assegnazione alla classe più alto livello possibile quando ci sono molte incognite / delle sottoclassi.

Sostituire la linea 6 con il seguente codice:

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

Esempio scenario in cui questa soluzione sarebbe utile e dove il livello più alto nome della classe dovrebbe essere impossibile da ottenere:

Si crea una classe, denominata "a" (class a:). Ha sottoclassi che hanno bisogno di accedervi (il genitore). Una sottoclasse si chiama "x1". In questo sottoclasse, il codice viene eseguito a.run_func().

Poi si crea un'altra classe, denominata "b", derivato dalla classe "A" (class b(a):). Dopo di che, un po 'di codice viene eseguito b.x1() (chiamando la funzione sub "x1" di B, un derivato sottoclasse). Questa funzione gestisce a.run_func(), chiamando la funzione "run_func" di classe "A", non la funzione "run_func" del suo genitore, "b" (come dovrebbe), perché la funzione che è stata definita in classe "a" è impostato per fare riferimento alla funzione di classe "a", come era suo padre.

Questo potrebbe causare problemi (per esempio, se la funzione a.run_func è stato cancellato) e l'unica soluzione senza dover riscrivere il codice nella classe a.x1 sarebbe ridefinire il x1 sottoclasse con codice aggiornato per tutte le classi derivate dalla classe "a" che avrebbe ovviamente difficile e non vale la pena.

Un'altra 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 ()

Si può facilmente accedere a classe esterna utilizzando metaclasse: dopo la creazione della classe esterna controllare è attribuire dict per tutte le classi (o applicare alcuna logica è necessario - la mia è solo esempio banale) e impostare valori corrispondenti:

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!

Con questo approccio, si può facilmente legare e fare riferimento due classi tra di loro.

Ampliando pensiero cogente @ di tsnorri, che il metodo esterno può essere un metodo statico :

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

Ora la linea in questione dovrebbe funzionare dal momento in cui viene effettivamente chiamato.

L'ultima riga nel codice sopra dà la classe interna un metodo statico che è un clone del metodo statico esterno.


Questo sfrutta due caratteristiche Python, che le funzioni sono oggetti e campo di applicazione è testuale .

  

Di solito, l'ambito locale fa riferimento a nomi locali del (testualmente) funzione corrente.

... o corrente class nel nostro caso. Così gli oggetti "locale" per la definizione della classe esterna (Inner e some_static_method) può deferire al direttamente all'interno di tale definizione.

ho trovato questo .

Ottimizzato per disabili a tua domanda, è la risposta:

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)

Sono sicuro che si può in qualche modo scrivere un decoratore per questo o qualcosa :)
/ Edit: po

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top