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

我遇到了这样的情况。

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

如何从 Inner类访问 Outer类的方法?

136937 次浏览

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

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

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

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

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

我找到 这个了。

为了回答你的问题,我做了调整:

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 内部类的目的是什么?

另一种可能性是:

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

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

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 mess_around(self):


outer_class_self = self


class Mooble():
def do_sthg_different(self):
...
outer_class_self.do_sthg()

另外... “ self”只在约定俗成的情况下使用,所以你可以这样做:

def do_sthg(self):
...


def mess_around(outer_class_self):


class Mooble():
def do_sthg_different(self):
...
outer_class_self.do_sthg()

可能会有人反对,因为你不能在外部类之外创建这个内部类... ... 但这不是真的:

class Bumblebee():


def do_sthg(self):
print "sthg"
    

def give_me_an_inner_class(outer_class_self):


class Mooble():
def do_sthg_different(self):
print "something diff\n"
outer_class_self.do_sthg()
return Mooble
    

然后,在几英里之外的某个地方:

blob = Bumblebee().give_me_an_inner_class()()
blob.do_sthg_different()

甚至把船推出一点,并扩展这个内部类(注意,要使 super()工作,必须将 Mooble的类签名改为 class Mooble(object))。

class InnerBumblebeeWithAddedBounce(Bumblebee().give_me_an_inner_class()):
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 give_me_an_inner_fatty_class(self):
class ExtendedInnerFatty(Fatty.InnerFatty):
pass
return ExtendedInnerFatty
                

fatty1 = Fatty()
fatty2 = Fatty()


innerFattyClass1 = fatty1.give_me_an_inner_fatty_class()
innerFattyClass2 = fatty2.give_me_an_inner_fatty_class()


print (issubclass(innerFattyClass1, Fatty.InnerFatty))
print (issubclass(innerFattyClass2, Fatty.InnerFatty))

对@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

现在该行应该在实际调用它时正常工作。

上面代码中的最后一行给予 Inside 类一个静态方法,它是 Out 静态方法的克隆。


这利用了两个 Python 特性,即 函数是对象范围是文本的

通常,局部作用域引用(文本上)当前函数的局部名称。

... 或目前的 同学们在我们的情况下。因此,外部类(Innersome_static_method)定义的“本地”对象可以在该定义中直接引用。

我已经创建了一些 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的包装器,self是对更高级别类的引用(来自函数内部运行的代码)。

    1. 创建一个名为 _parent_class的变量,它是对该函数的变量 self的引用,_subclass_container的子类可以访问它(避免与子类中的其他 self变量发生名称冲突)。

    2. 以字典/列表的形式返回子类/子类,这样调用 _subclass_container函数的代码就可以访问其中的子类。

  2. 在高级类中的 __init__函数(或者其他需要的地方) ,将返回的子类从函数 _subclass_container接收到变量 subclasses中。

  3. 将存储在 subclasses变量中的子类分配给更高级别类的属性。

以下是一些简化情节的小贴士:

使得将子类分配给更高级别类的代码更容易复制,并且可以用于从具有 __init__ < strong > 函数更改的更高级别类派生的类中:

在主代码的第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”(class b(a):)创建另一个名为“ b”的类 派生的。然后,一些代码运行 b.x1()(调用 b 的子函数“ x1”,这是一个派生的子类)。这个函数运行 a.run_func(),调用类“ a”的函数“ run _ func”,没有调用其父函数“ b”的函数“ run _ func”(应该是这样) ,因为在类“ a”中定义的函数被设置为引用类“ a”的函数,因为那是它的父函数。

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

你可以很容易地使用元类访问外部类: 在创建外部类之后,检查它对任何类(或者应用任何你需要的逻辑——我的只是一个普通的例子)的属性 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!

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

几年后的聚会... . 但是为了扩展 @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

再一次,一个美妙的答案,支持你迈克!

这太简单了:

输入:

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 fun1

B 类 fun1

您可以创建一个类来装饰内部类。

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

类 A 中的类方法,在本例中为 def add(cls, y=3),可以在 return cls.owner.x + y + 1中使用新的属性 owner

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


我们所能做的就是将 外面类的自变量作为类参数传递到内类中,并在外初始化时将外自变量初始化为内类

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

现在,在运行这个函数之后,它工作了