我有这样一种情况...
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
类的方法?
我有这样一种情况...
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
类的方法?
您正在尝试从内部类实例访问Outer的类实例。因此,只需使用factory-method来构建Inner实例,并将Outer实例传递给它。
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))
我找到了这个。
根据你的问题进行了修改:
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)
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
再次感谢您的出色回答,麦克!
您可以使用元类轻松地访问外部类:在创建外部类后,检查其属性字典以查找任何类(或应用您需要的任何逻辑-我的示例只是一种平凡的示例),并设置相应的值:
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!
通过这种方法,你可以轻松地将两个类绑定并相互引用。
我写了一些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()
。
然后创建另一个名为“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”的类更新代码,这显然很困难且不值得。
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 ()
您是不是想使用继承,而不是像这样嵌套类?在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:
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
self.<原始父类名称>
来访问父级,却会获得原始的类,而不是它们所属的新类。希望读者能够想象这种困难的情况,并理解为什么会提出这样的问题。 - Edward