如何从内部类访问外部类?

问题:如何从内部类访问外部类?

我有这样的情况

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

如何OuterInner类中访问类的方法?

I have a situation like so…

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

How can I access the Outer class’s method from the Inner class?


回答 0

嵌套类的方法不能直接访问外部类的实例属性。

请注意,即使您已经创建了内部类的实例,也不一定存在外部类的实例。

实际上,通常建议不要使用嵌套类,因为嵌套并不暗示内部类和外部类之间的任何特定关系。

The methods of a nested class cannot directly access the instance attributes of the outer class.

Note that it is not necessarily the case that an instance of the outer class exists even when you have created an instance of the inner class.

In fact, it is often recommended against using nested classes, since the nesting does not imply any particular relationship between the inner and outer classes.


回答 1

您正在尝试从内部类实例访问外部类的实例。因此,只需使用工厂方法构建内部实例并将外部实例传递给它即可。

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

You’re trying to access Outer’s class instance, from inner class instance. So just use factory-method to build Inner instance and pass Outer instance to it.

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

回答 2

也许我很生气,但这确实非常容易-事情是使您的内部类成为外部类的方法…

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

甚至将船伸出一点并扩展此内部类(要使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 ))

maybe I’m mad but this seems very easy indeed – the thing is to make your inner class inside a method of the outer class…

def do_sthg( self ):
    ...

def messAround( self ):

    outerClassSelf = self

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

Plus… “self” is only used by convention, so you could do this:

def do_sthg( self ):
    ...

def messAround( outerClassSelf ):

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

It might be objected that you can’t then create this inner class from outside the outer class… but this ain’t true:

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

then, somewhere miles away:

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

even push the boat out a bit and extend this inner class (NB to get super() to work you have to change the class signature of mooble to “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()

later

mrh1997 raised an interesting point about the non-common inheritance of inner classes delivered using this technique. But it seems that the solution is pretty straightforward:

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

回答 3

您是要使用继承,而不是像这样嵌套类吗?您所做的事情在Python中并没有多大意义。

您可以Outer通过仅Outer.some_method在内部类的方法中进行引用来访问’some_method ,但是它不会按预期的那样工作。例如,如果您尝试这样做:

class Outer(object):

    def some_method(self):
        # do something

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

…初始化Inner对象时会收到TypeError ,因为Outer.some_method期望接收Outer实例作为其第一个参数。(在上面的示例中,您基本上是在尝试some_method作为的类方法进行调用Outer。)

Do you mean to use inheritance, rather than nesting classes like this? What you’re doing doesn’t make a heap of sense in Python.

You can access the Outer‘s some_method by just referencing Outer.some_method within the inner class’s methods, but it’s not going to work as you expect it will. For example, if you try this:

class Outer(object):

    def some_method(self):
        # do something

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

…you’ll get a TypeError when initialising an Inner object, because Outer.some_method expects to receive an Outer instance as its first argument. (In the example above, you’re basically trying to call some_method as a class method of Outer.)


回答 4

您可以使用元类轻松访问外部类:创建外部类后,检查任何类的属性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!

使用这种方法,您可以轻松地相互绑定和引用两个类。

You can easily access to outer class using metaclass: after creation of outer class check it’s attribute dict for any classes (or apply any logic you need – mine is just trivial example) and set corresponding values:

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!

Using this approach, you can easily bind and refer two classes between each other.


回答 5

基于这个问题的另一个答案,我创建了一些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__

在主代码的第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()运行代码。

然后,从类“ a”()派生另一个名为“ b”的类class b(a):。之后,将运行一些代码b.x1()(调用b的子函数“ x1”(派生的子类))。该函数运行a.run_func(),调用类“ a” 的函数“ run_func ”,而不是其父级“ b”的函数“ run_func”(应如此),因为在类“ a”中定义的函数被设置为引用类“ a”的功能,因为它是其父级。

这将导致问题(例如,如果函数a.run_func已被删除),并且不重写类中代码的唯一解决方案a.x1将是x1使用从类“ a”派生的所有类的更新代码重新定义子类,这显然是困难且不值得的它。

I’ve created some Python code to use an outer class from its inner class, based on a good idea from another answer for this question. I think it’s short, simple and easy to understand.

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}

The main code, “production ready” (without comments, etc.). Remember to replace all of each value in angle brackets (e.g. <x>) with the desired value.

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

Explanation of how this method works (the basic steps):

  1. Create a function named _subclass_container to act as a wrapper to access the variable self, a reference to the higher level class (from code running inside the function).

    1. Create a variable named _parent_class which is a reference to the variable self of this function, that the sub-classes of _subclass_container can access (avoids name conflicts with other self variables in subclasses).

    2. Return the sub-class/sub-classes as a dictionary/list so code calling the _subclass_container function can access the sub-classes inside.

  2. In the __init__ function inside the higher level class (or wherever else needed), receive the returned sub-classes from the function _subclass_container into the variable subclasses.

  3. Assign sub-classes stored in the subclasses variable to attributes of the higher level class.

A few tips to make scenarios easier:

Making the code to assign the sub classes to the higher level class easier to copy and be used in classes derived from the higher level class that have their __init__ function changed:

Insert before line 12 in the main code:

def _subclass_init(self):

Then insert into this function lines 5-6 (of the main code) and replace lines 4-7 with the following code:

self._subclass_init(self)

Making subclass assigning to the higher level class possible when there are many/unknown quantities of subclasses.

Replace line 6 with the following code:

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

Example scenario of where this solution would be useful and where the higher level class name should be impossible to get:

A class, named “a” (class a:) is created. It has subclasses that need to access it (the parent). One subclass is called “x1”. In this subclass, the code a.run_func() is run.

Then another class, named “b” is created, derived from class “a” (class b(a):). After that, some code runs b.x1() (calling the sub function “x1” of b, a derived sub-class). This function runs a.run_func(), calling the function “run_func” of class “a”, not the function “run_func” of its parent, “b” (as it should), because the function which was defined in class “a” is set to refer to the function of class “a”, as that was its parent.

This would cause problems (e.g. if function a.run_func has been deleted) and the only solution without rewriting the code in class a.x1 would be to redefine the sub-class x1 with updated code for all classes derived from class “a” which would obviously be difficult and not worth it.


回答 6

我发现了这个

调整了适合您的问题:

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)

我确定您可以以某种方式为此目的编写装饰器

相关:python内部类的目的是什么?

I found this.

Tweaked to suite your 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)

I’m sure you can somehow write a decorator for this or something

related: What is the purpose of python’s inner classes?


回答 7

另一种可能性:

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

Another possibility:

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

回答 8

扩展@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类提供了一个静态方法,该方法是Outer静态方法的克隆。


这利用了两个Python功能,即功能是对象作用域是文本

通常,本地范围引用(按文本形式)当前函数的本地名称。

…或本例中的当前Class。因此Innersome_static_method可以直接在该定义内引用“外部”类(和)定义的“局部”对象。

Expanding on @tsnorri’s cogent thinking, that the outer method may be a static method:

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

Now the line in question should work by the time it is actually called.

The last line in the above code gives the Inner class a static method that’s a clone of the Outer static method.


This takes advantage of two Python features, that functions are objects, and scope is textual.

Usually, the local scope references the local names of the (textually) current function.

…or current class in our case. So objects “local” to the definition of the Outer class (Inner and some_static_method) may be referred to directly within that definition.


回答 9

几年迟到了….但是扩大@mike rodent的精彩的回答,我提供我自己的例子低于正好显示了如何灵活的他的解决办法是,为什么它应该是(或应该已经被)接受回答。

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

输出:

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

再次,一个很好的答案,迈克的道具!

A few years late to the party…. but to expand on @mike rodent‘s wonderful answer, I’ve provided my own example below that shows just how flexible his solution is, and why it should be (or should have been) the accepted answer.

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

Output:

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

Again, a wonderful answer, props to you mike!


回答 10

这太简单了:

输入:

class A:
    def __init__(self):
        pass

    def func1(self):
        print('class A func1')

    class B:
        def __init__(self):
            a1 = A()
            a1.func1()

        def func1(self):
            print('class B func1')

b = A.B()
b.func1()

输出量

A类func1

B类func1

It is too simple:

Input:

class A:
    def __init__(self):
        pass

    def func1(self):
        print('class A func1')

    class B:
        def __init__(self):
            a1 = A()
            a1.func1()

        def func1(self):
            print('class B func1')

b = A.B()
b.func1()

Output

class A func1

class B func1