Подтвердить что ты не робот

Доступ к внешнему классу из внутреннего класса в 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?

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

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

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

Ответ 3

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

def do_sthg( self ):
    ...

def messAround( self ):

    outerClassSelf = self

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

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

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

Ответ 4

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

Вы можете получить доступ к Outer some_method, просто указав Outer.some_method внутри внутренних методов класса, но он не будет работать так, как вы ожидаете. Например, если вы попробуете это:

class Outer(object):

    def some_method(self):
        # do something

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

... вы получите TypeError при инициализации объекта Inner, потому что Outer.some_method ожидает получить экземпляр Outer в качестве своего первого аргумента. (В приведенном выше примере вы в основном пытаетесь вызвать some_method как метод класса Outer.)

Ответ 5

Основываясь на замечательной идее, ответ на тот же вопрос, на который я отвечаю (в fooobar.com/questions/105460/...), объяснил, поскольку я хотел создать собственное решение хорошего качества на вопрос, я придумал ответ на 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>}

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

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

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

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

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

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

Несколько советов для облегчения сценариев:

Создание кода для назначения подкласс классам более высокого уровня, которые легче копировать и использоваться в классах, полученных из класса более высокого уровня, которые имеют функцию __init__ :

Вставить перед строкой 12 в основном коде:

    def _subclass_init(self):

Затем вставьте в это функциональные строки 5-6 (основного кода) и замените строки 4-7 следующим кодом:

        self._subclass_init(self)

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

Заменить строку 6 следующим кодом:

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

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

Создается класс с именем "a" (class a:). Он имеет подклассы, которым необходимо получить к нему доступ (родительский). Один подкласс называется "x1". В этом подклассе выполняется код a.run_func().

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

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

Ответ 6

Вы можете легко получить доступ к внешнему классу с помощью метакласса: после создания внешнего класса проверьте его атрибут 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 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!

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

Ответ 7

я нашел этот.

Измените свой вопрос, это ответ:

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: kinda

Ответ 8

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

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

Ответ 9

Развернув на @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

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

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


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

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

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