嵌套的Python类需要访问封闭类中的变量

时间:2011-06-17 20:47:42

标签: python scope nested-class

我已经看到了一些“解决方案”,但每次解决方案似乎都是“不要使用嵌套类,在外部定义类,然后正常使用它们”。我不喜欢这个答案,因为它忽略了我选择嵌套类的主要原因,也就是说,要创建一个可以访问所有子类实例的常量池(与基类相关联)。

以下是示例代码:

class ParentClass:

    constant_pool = []
    children = []

    def __init__(self, stream):
        self.constant_pool = ConstantPool(stream)
        child_count = stream.read_ui16()
        for i in range(0, child_count):
            children.append(ChildClass(stream))

    class ChildClass:

        name = None

        def __init__(self, stream):
            idx = stream.read_ui16()
            self.name = constant_pool[idx]

所有类都传递一个param,这是一个自定义比特流类。我的目的是找到一个解决方案,它不需要我在ChildClass中读取ChildClass的idx值。所有儿童班级的阅读都应该在儿童班上完成。

此示例过于简化。常量池不是我需要的所有子类的唯一变量。 idx变量不是从流阅读器中读取的唯一内容。

这在python中甚至可能吗?有没有办法访问父母的信息?

6 个答案:

答案 0 :(得分:11)

尽管我有点“赞美”评论(公平竞争称之为!),实际上有办法实现你想要的东西:不同的继承途径。一对夫妇:

  1. 编写一个装饰器,它在声明类之后对其进行内省,找到内部类,并将外部类中的属性复制到它们中。

  2. 使用元类做同样的事情。

  3. 这是装饰者的方法,因为它是最直接的:

    def matryoshka(cls):
    
        # get types of classes
        class classtypes:
            pass
        classtypes = (type, type(classtypes))
    
        # get names of all public names in outer class
        directory = [n for n in dir(cls) if not n.startswith("_")]
    
        # get names of all non-callable attributes of outer class
        attributes = [n for n in directory if not callable(getattr(cls, n))]
    
        # get names of all inner classes
        innerclasses = [n for n in directory if isinstance(getattr(cls, n), classtypes)]
    
        # copy attributes from outer to inner classes (don't overwrite)
        for c in innerclasses:
            c = getattr(cls, c)
            for a in attributes:
                if not hasattr(c, a):
                    setattr(c, a, getattr(cls, a))
    
        return cls
    

    以下是一个简单的使用示例:

    @matryoshka
    class outer(object):
    
        answer = 42
    
        class inner(object):
    
            def __call__(self):
                print self.answer
    
    outer.inner()()   # 42
    

    但是,我不禁想到其他答案中提出的一些想法会更好地为你服务。

答案 1 :(得分:7)

这里你不需要两节课。这是您以更简洁的方式编写的示例代码。

class ChildClass:
    def __init__(self, stream):
        idx = stream.read_ui16()
        self.name = self.constant_pool[idx]

def makeChildren(stream):
    ChildClass.constant_pool = ConstantPool(stream)
    return [ChildClass(stream) for i in range(stream.read_ui16())]

欢迎使用Python。类在运行时是可变的。享受。

答案 2 :(得分:2)

您可以通过名称访问父类:

class ChildClass:

    name = None

    def __init__(self, stream):
        idx = stream.read_ui16()
        self.name = ParentClass.constant_pool[idx]

然后,我不确定我理解你想要实现的目标。

答案 3 :(得分:1)

另一种需要考虑的替代设计:

当您发现自己尝试将类用作命名空间时,将内部类放入自己的模块中并将外部类全局变量的属性设置为更有意义。换句话说,如果你从未打算实例化你的ParentClass,那么它只是作为一个荣耀的模块。

全局变量在大多数编程语言中都说不好,但它们在Python中并不是真正的全局变量,而且很好地封装在模块中。

答案 4 :(得分:0)

嗯,以下工作(从您的示例中进一步简化)。请注意,您不必在类级别“声明”成员变量,如C ++ / C#/ Java等,只需在self __init__内的class ParentClass: def __init__(self): self.constant_pool = ["test"] self.ChildClass.constant_pool = self.constant_pool self.children = [self.ChildClass()] class ChildClass: def __init__(self): self.name = self.constant_pool[0] print "child name is", self.name p = ParentClass() # Prints "child name is test" 上设置它们:

{{1}}

请注意,如果没有嵌套子类,您仍然可以执行相同的操作。

答案 5 :(得分:0)

你的问题使用了子类这个词,所以我很想解释你的问题。和其他已经回答的人一样,我不确定我理解你在寻找什么。

class ParentClass(object):
  constant_pool = [c1, c2, c3]
  def __init__(self):
    # anything not included in your question

class ChildClass(ParentClass):
  def __init__(self, stream):
    ParentClass.__init__(self)
    self.name = ParentClass.constant_pool[stream.read_ui16()]

stream = get_new_stream()
children = []
for count in range(stream.read_ui16()):
  children.append(ChildClass(stream))

此代码使用继承从ParentClass(以及所有方法等)派生ChildClass。 constant_pool是ParentClass本身的一个属性,虽然可以将其视为ParentClass或ChildClass的任何实例的属性(在self.constant_pool中说ChildClass.__init__将等同于上述内容,但在我看来,误导)。

不必嵌套类定义。将ChildClass的定义嵌套在ParentClass中只意味着ChildClass是ParentClass的属性,仅此而已。它不会使ChildClass的实例从ParentClass继承任何内容。