问题:如何从内部类访问外部类?
我有这样的情况
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
类中访问类的方法?
回答 0
嵌套类的方法不能直接访问外部类的实例属性。
请注意,即使您已经创建了内部类的实例,也不一定存在外部类的实例。
实际上,通常建议不要使用嵌套类,因为嵌套并不暗示内部类和外部类之间的任何特定关系。
回答 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
也许我很生气,但这确实非常容易-事情是使您的内部类成为外部类的方法…
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 ))
回答 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
。)
回答 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!
使用这种方法,您可以轻松地相互绑定和引用两个类。
回答 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>}
有关此方法如何工作的说明(基本步骤):
创建一个命名
_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()
运行代码。
然后,从类“ 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”派生的所有类的更新代码重新定义子类,这显然是困难且不值得的它。
回答 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)
我确定您可以以某种方式为此目的编写装饰器
回答 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 ()
回答 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静态方法的克隆。
通常,本地范围引用(按文本形式)当前函数的本地名称。
…或本例中的当前Class。因此Inner
,some_static_method
可以直接在该定义内引用“外部”类(和)定义的“局部”对象。
回答 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
再次,一个很好的答案,迈克的道具!
回答 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