151

我有这样的情况...

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

4

13 回答 13

109

您正在尝试从内部类实例访问外部类实例。所以只需使用工厂方法来构建内部实例并将外部实例传递给它。

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()
于 2011-08-11T23:44:28.647 回答
92

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

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

事实上,通常建议不要使用嵌套类,因为嵌套并不意味着内部类和外部类之间有任何特定的关系。

于 2010-01-07T23:54:24.477 回答
37

也许我很生气,但这似乎确实很容易 - 事情是让你的内部类在外部类的方法中......

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()工作,您必须更改 to 的类签名Moobleclass 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))
于 2011-08-22T19:38:17.530 回答
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)

我相信你可以以某种方式为此或其他东西写一个装饰器

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

于 2011-05-16T12:37:35.673 回答
5

聚会晚了几年....但是为了扩展@mike rodent的精彩答案,我在下面提供了我自己的示例,说明了他的解决方案是多么灵活,以及为什么它应该(或应该被接受回答。

蟒蛇 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

再一次,一个精彩的答案,麦克的道具!

于 2020-03-29T00:02:56.273 回答
4

我创建了一些 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()运行。

然后创建另一个名为“b”的类,它派生自类“a”(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”派生的所有类的子类,这显然是困难且不值得的它。

于 2016-01-31T19:57:09.210 回答
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!

使用这种方法,您可以轻松地在彼​​此之间绑定和引用两个类。

于 2017-06-06T14:29:34.693 回答
3

你的意思是使用继承,而不是像这样嵌套类?你正在做的事情在 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()

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

于 2010-01-08T00:01:25.620 回答
3

另一种可能:

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 ()
于 2011-07-29T16:53:47.527 回答
2

我们可以做的是在内部类中传递外部类的 self 变量作为类参数,并在外部初始化下初始化内部类,将外部自我传递到内部

class Outer:
    def __init__(self):
        self.somevalue=91
        self.Inner=self.Inner(self)
    def SomeMethod(self):
        print('This is Something from Outer Class')

    class Inner:
        def __init__(self,Outer)
            self.SomeMethod=Outer.SomeMethod
            self.somevalue=Outer.somevalue
    
        def SomeAnotherMethod(self):
            print(self.somevalue)
            self.SomeMethod()        

>>>f=Outer()
>>>f.Inner.SomeAnotherMethod() 
91
This is Something from Outer Class

现在运行此功能后,它可以工作

于 2021-05-28T04:49:07.627 回答
1

扩展@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 的两个特性,即函数是对象作用域是文本

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

...或在我们的案例中的当前课程。因此,外部类 (Innersome_static_method) 定义的“本地”对象可以在该定义中直接引用。

于 2015-10-20T16:57:49.977 回答
0

您可以创建一个类来装饰内部类。在这种情况下@inner。

因为这是一个装饰器:Outer.A = inner(Outer.A)。一旦您的代码需要 Outer.A,它将被执行inner.__get__方法,该方法返回原始类 (A),并在其上设置了新属性:A.owner = Outer。

类 A 中的类方法,在这种情况下,可以在 处def add(cls, y=3)使用新属性。ownerreturn cls.owner.x + y + 1

setattr(owner, name, self.inner), 打破了描述符,因为owner.name => Outer.A => A不再是类内部的实例。

希望这可以帮助。

    class inner:
    
        def __init__(self, inner):
            self.inner = inner
    
        def __get__(self, instance, owner):
            print('__get__ method executed, only once... ')
            name = self.inner.__name__
            setattr(self.inner, 'owner', owner) 
            setattr(owner, name, self.inner) # breaks descriptor
            return self.inner #returns Inner
    
    class Outer:
        x = 1
    
        @inner
        class A:
    
            @classmethod
            def add(cls, y=3):
                return cls.owner.x + y + 1
    
    print(Outer.A.add(0)) # First time executes inner.__get__ method
    print(Outer.A.add(0)) # Second time not necessary.

    >> __get__ method executed, only once... 
    >> 2
    >> 2

于 2020-11-26T21:22:31.577 回答
-5

太简单了:

输入:

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类功能1

B类功能1

于 2020-04-22T21:57:36.733 回答