在嵌套类中,如何从Python中的嵌套类访问外部类的元素?

时间:2012-12-10 09:23:01

标签: python class nested

我有这种情况,我需要让嵌套类将项目附加到外部类的列表中。 Heres伪代码类似于我想要做的事情。我怎么去开始工作?

class Outer(object):
  outerlist = []
  class Inner(object):
    def __call__(self, arg1):
      outerlist.append(arg1)

if __name__ == "__main__":
  f = Outer()
  f.Inner("apple")
  f.Inner("orange")

  print f.outerlist()

我希望看到这一点 - apple, orange

详细说明:
OS X,Python 2.7

5 个答案:

答案 0 :(得分:4)

您只能使用完整的全局名称访问外部类:

class Outer(object):
    outerlist = []
    class Inner(object):
        def __call__(self, arg1):
            Outer.outerlist.append(arg1)

在python中,通常不需要在任何情况下嵌套类。有一些用例,在函数中定义一个类是有意义的(使用作用域的变量),但很少需要嵌套类。

答案 1 :(得分:2)

这将产生预期的结果。

注意使用__new__(A行)。这意味着内部只需附加列表,而不是正确地进行任何构造。此外,要访问包含类的类属性,只需使用外部类的名称(第B行)。

最后看到第C行。列表不是函数。您的原始代码中有一些额外的括号。

class Outer(object):
    outerlist = []
    class Inner(object):
        def __new__(self, arg1):                #A
            Outer.outerlist.append(arg1)        #B

f = Outer()
f.Inner("apple")
f.Inner("orange")
print f.outerlist                               #C

答案 2 :(得分:2)

既然我理解了你的设计,你就会发生错误。

首先,外面是一个阶级;它没有得到__call__。你的第17行只是构造一个空的Outer对象而不对它做任何事情。如果你想“调用”Outer对象,你可以定义一个__init__方法 - 或者像Sheena建议的那样,定义一个__new__并拦截初始化,因为你实际上并没有无论如何都需要初始化的对象。

老实说,我认为不理解__call__如何运作的人应该尝试构建一些像这样棘手的东西。但如果你坚持,请继续阅读。

在类中而不是实例中收集这类东西是一种非常奇怪的,可能很糟糕的设计。请记住,类变量实际上是全局变量,所有这些都需要。如果你尝试重新使用Outer,或者从多个线程/事件处理程序/ greenlets /中使用,那么这些用法最终会相互踩踏。即使你认为现在不太可能成为一个问题,它可能会在未来的某个时候出现。

您可以创建一个Outer实例,并将其成员用作装饰器。例如:

from outer_library import Outer

outer = Outer()

@outer.get("/")
…

但我不确定那会好得多。这里的整个设计似乎涉及在模块级执行操作,即使看起来你只是定义了正常的函数并在最后调用了一个函数。你设法让自己迷惑的事实应该证明这是一个令人困惑的设计。

但是如果您想要这样做,您可能想要做的是在Outer.__init__方法中定义类,并将它们分配给实例成员。类是一等值,可以像任何其他值一样分配给变量。然后,使用这些类的__init__(或__new__)方法完成您想要的工作,使类模拟函数。

这可能看起来令人困惑或误导。但要记住,你要做的事情的重点在于以一种看起来像方法的方式使用一个类,因此这种混淆是问题所固有的。但如果您愿意,可以将装饰器编写为函数(在本例中,作为Outer的常规实例方法);它只是使问题的另一部分变得更难而不是这部分。

设计类似这样的东西的更常规的方法是使Outer成为一个完全正常的类,人们可以将其子类化或创建实例,并提供一种明确的非奇特方式来将处理程序方法或函数附加到网址。然后,一旦它工作,设计一种方法来简化装饰器注册处理程序。

答案 3 :(得分:0)

为什么不将外部类实例作为参数传递给内部类方法?您可以通过这种方式访问​​外部类实例的成员。

  class Outer(object):
    outerlist = []
    class Inner(object):
      def __init__(self, outer_self):
        self.outer = outer_self
      def __call__(self, arg1):
        self.outer.outerlist.append(arg1)

 if __name__ == "__main__":
   f = Outer()
   i = f.Inner(f)
   i("apple")
   i("orange")

   print f.outerlist

答案 4 :(得分:0)

我认为picmate指出的选项(将外部类作为内部类的输入)是这个特定问题的一个很好的选择。请注意,它也可以工作,而不必嵌套'这些课程(在我看来,由于不必要,所以要避免这种情况)。请注意,我还在内部类中嵌入了内部类的初始化(这一步不是严格需要的,但我将其包含在此处用于说明目的):

class Outer(object):
  outerlist = []
  def __init__(self):
    self.Inner=Inner(Outer=self)
  def get_basket(self):
    print "Outer basket: %s" %(self.outerlist)

class Inner(object):
  def __init__(self,Outer):
    self.Outer=Outer
  def __call__(self, arg1):
    self.Outer.outerlist.append(arg1)
  def get_basket(self):
    print "Inner basket: %s" %(self.Outer.outerlist)

if __name__ == "__main__":
  f = Outer()
  print "Initial state"
  f.get_basket()
  f.Inner.get_basket()
  f.Inner("apple")
  f.Inner("orange")
  print "Final state"
  f.get_basket()
  f.Inner.get_basket()