Доступ к внешнему классу из внутреннего класса в python


у меня такая ситуация...

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

как я могу получить доступ к Outer метод класса из Inner класса?

Edit -- Спасибо за ответы. Я прихожу к выводу, что мне нужно переоценить, как я разработал это для реализации и придумать более надежный метод.

9 63

9 ответов:

методы вложенного класса не могут напрямую обращаться к атрибутам экземпляра внешнего класса.

обратите внимание, что не обязательно экземпляр внешнего класса существует, даже если вы создали экземпляр внутреннего класса.

на самом деле, часто рекомендуется не использовать вложенные классы, так как вложенность не подразумевает каких-либо конкретных отношений между внутренними и внешними классами.

вы пытаетесь получить доступ к экземпляру внешнего класса, из экземпляра внутреннего класса. Поэтому просто используйте factory-метод для создания внутреннего экземпляра и передачи ему внешнего экземпляра.

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

может быть, я злюсь, но это кажется очень легко на самом деле - дело в том, чтобы сделать ваш внутренний класс внутри метода внешнего класса...

def do_sthg( self ):
    ...

def messAround( self ):

    outerClassSelf = self

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

плюс... "self" используется только по соглашению, поэтому вы можете сделать это:

def do_sthg( self ):
    ...

def messAround( outerClassSelf ):

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

можно возразить, что вы не можете создать этот внутренний класс из внешнего класса... но это неправда:

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

затем, где-то за много миль:

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

даже вытолкнуть лодку немного и продлить это внутренний класс (NB чтобы получить super () для работы вам нужно изменить сигнатуру класса mooble на "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()

позже

mrh1997 поднял интересный вопрос о необычном наследовании внутренних классов, поставляемых с использованием этой техники. Но кажется, что решение довольно простое:

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

вы хотите использовать наследование, а не вложенные классы, как это? То, что вы делаете, не имеет никакого смысла в Python.

вы можете получить доступ к Outer ' s some_method, просто ссылаясь на Outer.some_method внутри методов внутреннего класса, но это не будет работать так, как вы ожидаете. Например, если вы попробуете это:

class Outer(object):

    def some_method(self):
        # do something

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

...вы получите TypeError при инициализации

я создал некоторый код Python для использования внешний класс из его внутренний класс, основанный на хорошей идее от другого ответ по этому вопросу. Я думаю, что это коротко, просто и легко понять.

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}

основной код, "готов" (без комментариев и т. д.). Не забудьте заменить все значения в угловых скобках (например,<x>) С нужным значением.

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

объяснение того, как этот метод работы (основные этапы):

  1. создать функцию с именем _subclass_container в качестве оболочки для доступа к переменной self, ссылка на класс более высокого уровня (из кода, выполняемого внутри функции).

    1. создать переменную с именем _parent_class, который является ссылкой на переменную self этой функции, что подклассы _subclass_container может получить доступ (избегает конфликтов имен с другими self переменные в подклассы).

    2. возвращает подкласс / подклассы в виде словаря / списка, поэтому код вызывает _subclass_container функция может получить доступ к подклассам внутри.

  2. на __init__ функция внутри класса более высокого уровня (или там, где это необходимо), получить возвращенные подклассы из функции _subclass_container в переменную subclasses.

  3. назначить подклассы, хранящиеся в subclasses переменной атрибуты высшего класса.

несколько советов, чтобы сделать сценарии проще:

что делает код для назначения подклассов классу более высокого уровня проще копировать и использовать в классах, производных от класса более высокого уровня, которые имеют свои__init__) является. Оно имеет подклассы, которые должны получить к нему доступ (родитель). Один подкласс называется "x1". В этом подклассе код a.run_func() запускается.

затем создается другой класс с именем "b",производные из класса "а" (class b(a):). После этого какой-то код работает b.x1() (вызов подфункции " x1 " из B, производного подкласса). Эта функция работает a.run_func(), вызывая функцию "run_func" класса "a",не функция "run_func" своего родителя, "b" (как и должно быть), потому что функция, которая была определена в классе "a", установлена для ссылки на функцию класса" A", поскольку это был ее родитель.

это вызовет проблемы (например, если функция a.run_func удален) и единственное решение без переписывания кода в класс a.x1 было бы переопределить подкласс x1 с обновленным кодом для всех классов, производных от класса "А", которая, очевидно, будет сложно и не стоит.

другая возможность:

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

вы можете легко получить доступ к внешнему классу с помощью metaclass: после создания внешнего класса проверьте его атрибут dict для любых классов (или примените любую логику, которая вам нужна - мой просто тривиальный пример) и установите соответствующие значения:

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!

используя этот подход, вы можете легко связать и передать два класса между собой.

расширяя убедительное мышление @tsnorri, что внешний метод может быть статический метод:

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

Теперь рассматриваемая строка должна работать к моменту ее фактического вызова.

последняя строка в приведенном выше коде дает внутреннему классу статический метод, который является клоном внешнего статического метода.


Это использует две функции Python, что функции являются объектами и объем текстовая.

обычно локальная область ссылается на локальные имена (текстуально) текущей функции.

...или текущий класс в нашем случае. Итак, объекты "локальные" для определения внешнего класса (Inner и some_static_method) может упоминаться непосредственно в этом определении.

нашел этой.

Tweaked, чтобы удовлетворить ваш вопрос, это ответ:

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)

Я уверен, что можно как-то написать декоратор для этого или что-то :)
/ edit:вроде