5

我有这种情况,我需要要求一个嵌套类将项目附加到外部类的列表中。这是类似于我试图做的伪代码。我将如何让它发挥作用?

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

4

5 回答 5

4

这将产生预期的结果。

注意__new__(A行)的使用。这意味着 Inner 不会正确地做任何构造工作,而是附加列表。此外,要访问包含类的类属性,只需使用外部类的名称(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
于 2012-12-10T09:33:49.030 回答
3

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

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

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

于 2012-12-10T09:25:51.790 回答
2

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

  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
于 2016-09-01T17:43:13.927 回答
1

既然我了解了您的设计,那么您做的事情都错了。

首先,Outer 是一个类;它没有得到__call__编辑。您的第 17 行只是要构造一个空Outer对象并且什么都不做。如果您想“调用”该Outer对象,您可以定义一个__init__方法——或者,正如 Sheena 所建议的,定义 a__new__并拦截初始化,因为您实际上并不需要初始化的对象。

老实说,我不认为那些还不了解如何__call__工作的人应该尝试构建像这样棘手的东西。但是,如果您坚持,请继续阅读。

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

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

from outer_library import Outer

outer = Outer()

@outer.get("/")
…

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

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

这可能看起来令人困惑或误导。但是请记住,您尝试做的全部重点是以一种看起来像方法的方式使用类,因此这种混淆是问题固有的。但是,如果您愿意,可以将装饰器编写为函数(在这种情况下,作为 的普通实例方法Outer);它只是使问题的不同部分变得更难,而不是这部分。

设计这样的东西的一种更正常的方法是创建Outer一个完全正常的类,人们可以对其进行子类化或创建实例,并提供一种显式的非花哨方式来将处理程序方法或函数附加到 URL。然后,一旦它起作用,设计一种方法来简化使用装饰器注册的处理程序。

于 2012-12-10T10:05:17.223 回答
-1

我认为 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()
于 2017-11-23T09:50:03.247 回答