如何从内部类访问外部类?
- 2025-02-12 10:04:00
- admin 原创
- 72
问题描述:
我遇到了这样的情况......
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
?
解决方案 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()
解决方案 2:
嵌套类的方法不能直接访问外部类的实例属性。
请注意,即使创建了内部类的实例,也不一定存在外部类的实例。
事实上,通常建议不要使用嵌套类,因为嵌套并不意味着内部类和外部类之间存在任何特定的关系。
解决方案 3:
也许我疯了,但这确实看起来很容易——关键是让你的内部类成为外部类的方法......
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
"
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))
解决方案 4:
我发现了这一点。
调整以适合您的问题:
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 内部类的用途是什么?
解决方案 5:
迟到了几年......但为了扩展@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
再次,这是一个非常精彩的回答,向你致敬,迈克!
解决方案 6:
您可以使用元类轻松访问外部类:创建外部类后,检查任何类的属性字典(或应用您需要的任何逻辑 - 我的只是简单的例子)并设置相应的值:
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!
使用这种方法,您可以轻松地将两个类绑定并相互引用。
解决方案 7:
我根据这个问题的另一个答案中的一个好主意,创建了一些 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
,即对更高级别类的引用(从函数内部运行的代码)。
1. 创建一个名为的变量`_parent_class`,它是对此函数变量的引用`self`,其子类`_subclass_container`可以访问(避免与`self`子类中的其他变量发生名称冲突)。
2. 将子类/子类作为字典/列表返回,以便调用该`_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()
(调用派生子类 b 的子函数“x1”)。此函数运行a.run_func()
,调用类“a”的函数“run_func”,而不是其父类“b”的函数“run_func”(应该如此),因为在类“a”中定义的函数被设置为引用类“a”的函数,因为那是它的父类。
这会导致问题(例如,如果函数a.run_func
已被删除),并且不重写类中的代码的唯一解决方案a.x1
是x1
使用更新的代码重新定义从类“a”派生的所有类的子类,这显然很困难并且不值得。
解决方案 8:
您的意思是使用继承,而不是像这样嵌套类?您所做的在 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()
...初始化对象时会收到 TypeError Inner
,因为Outer.some_method
期望接收一个Outer
实例作为其第一个参数。(在上面的例子中,您基本上是尝试将其some_method
作为类方法调用Outer
。)
解决方案 9:
另一种可能性:
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 ()
解决方案 10:
我们可以做的是将外部类的 self 变量作为类参数传递给内部类,然后在外部 init 下初始化内部类,并将外部自身传递给内部
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
现在运行此功能后,它就可以工作了
解决方案 11:
扩展@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 的两个特性,即函数是对象,作用域是文本。
通常,本地范围引用(文本)当前函数的本地名称。
...或者在我们的例子中是当前类Inner
。因此,外部类(和)定义的“本地”对象some_static_method
可在该定义中直接引用。
解决方案 12:
感谢@mike-rodent的精彩回答,也感谢@tre-x。
根据您的做法,三级类嵌套定义及相互调用的示例如下。
# [0 - CLASSDEBUG_TEST, 1 - ONELINEND_SYSEXIT]
_DF = (True, True)
class rootcls_stackoverflow_q2024566_a60908562(object):
# https://stackoverflow.com/a/60908562
def __init__(self):
pass
class innercls(object):
pass
def print_hi(self):
print(f"hi rootcls")
def call_innercls_function(self):
parent = self.innercls_parent("Barbar")
parent.print_hi()
child = parent.innercls_child("Foofoo")
child.print_hi()
util = self.innercls_util()
util.get_current_format_time()
util.get_python_interpreter_path()
def innercls_util(self):
rootcls = self
class innercls_util(rootcls.innercls):
def get_current_format_time(self):
import time
time_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
print(time_str)
return time_str
def get_python_interpreter_path(self):
import sys
pypath_interpreter = sys.executable
print(pypath_interpreter)
return pypath_interpreter
return innercls_util() # Be sure to include parentheses
def innercls_parent(self, name):
rootcls = self
class innercls_parent(rootcls.innercls):
def __init__(self, name):
self.name = name
self.children = []
def print_hi(self):
print(f"hi {self.name} of innercls_parent")
def call_rootcls_function(self):
print(f"call root class function:", end = " ")
rootcls.print_hi()
def innercls_child(self, name, rootcls=rootcls):
rootcls = rootcls
parentcls = self
class innercls_child(rootcls.innercls):
def __init__(self, name):
self.name = name
self.parent = parentcls
parentcls.children.append(self)
def print_hi(self):
print(f"hi {self.name} of innercls_child")
def call_parentcls_function(self):
parentcls.print_hi()
def call_rootcls_function(self):
print(f"call root class function:", end = " ")
rootcls.print_hi()
return innercls_child(name)
return innercls_parent(name)
def innercls_test(self):
rootcls = self
class innercls_test(rootcls.innercls):
def __init__(self):
pass
def test_doit(self):
parent = rootcls.innercls_parent("Bar")
child1 = parent.innercls_child("Foo")
child2 = parent.innercls_child("World")
print(
child1.name,
parent.children[0].name,
child2.name,
parent.children[1].name,
child2.parent.children[0].parent.children[1].parent.name,
child1.parent.children[1].parent.children[0].parent.name
)
rootcls.print_hi()
rootcls.call_innercls_function()
parent.print_hi()
parent.call_rootcls_function()
child1.print_hi()
child2.print_hi()
return innercls_test()
if ('_DF' in locals() or '_DF' in globals()) and _DF[0]:
instance_rootcls = rootcls_stackoverflow_q2024566_a60908562()
instance_innercls_test = instance_rootcls.innercls_test()
instance_innercls_test.test_doit()
if ('_DF' in locals() or '_DF' in globals()) and _DF[1]:
import sys; print(); sys.exit(0)
解决方案 13:
您可以创建一个类来装饰内部类。在本例中为 @inner。
因为这是一个装饰器:Outer.A = inner(Outer.A)。一旦您的代码需要 Outer.A,就会执行inner.__get__
方法,该方法返回原始类 (A) 并在其上设置新属性:A.owner = Outer。
在这种情况下,类 A 中的类方法可以在处def add(cls, y=3)
使用新属性。owner
`return 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
解决方案 14:
可以通过将外部类对象解析为内部类来实现。
class Outer():
def __init__(self,userinput):
self.userinput = userinput
def outer_function(self):
self.a = self.userinput + 2
class Inner():
def inner_function(self):
self.b = self.a + 10
定义完之后,需要运行该函数
m = Outer(3)
m.outer_function()
print (m.a)
#this will output 5
现在它有了外部类的变量。然后,它需要运行内部类函数。
m.Inner.inner_function(m)
外部类的对象m被解析到内部类的函数中(括号内),现在内部类函数正在从外部类访问self.a。
print (m.b)
#this will output 15
解决方案 15:
class Outer():
class Inner():
def __init__(self, o):
self._outer=o
def demo(self):
print("I am the inner class and I call the outer class now")
self._outer.whoami()
def __init__(self):
self._inner=Outer.Inner(self)
def whoami(self):
print("I am the outer class")
def demo(self):
self._inner.demo()
myOuter=Outer()
myOuter.demo()
解决方案 16:
这太简单了:
输入:
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